伯乐共勉

讨论。NET专区
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

symbian 开发技巧集

Posted on 2007-02-01 14:06  伯乐共勉  阅读(594)  评论(0编辑  收藏  举报
接着谈谈程序的本地化实施,只有两个重要法则要记住:一是不要在c++源文件中嵌入文本,另一个就是不要对数据缓冲区尺寸进行绝对编码(在众多的数据转换中就看出来了)。
在示例代码的使用中有很多术语要遵守,下面我们就要谈谈这些个术语。注意我们先阐明一些规则用的术语,这些术语表明了相关规则的作用。

viability 如果代码不遵从这个规则那将无法工作。
reliability 如果代码不遵从这个规则那可能无法好好工作。
maintainability 如果代码不遵从这个规则那可能很难维护。
readability 如果代码不遵从这个规则那可能很难理解。
convention 如果代码不遵从这个规则那将不符合约定束成。

同样规则们也被标记为一般的
c++代码规则
symbain OS特定规则
Nokia推荐规则

--------------现在列举并解释这些术语-------------------
Assertions
——reliability (symbian)
  一个函数体可以由一系列的_ASSERT_ALWAYS()宏开始,以用来检验参数的有效性。
  如果函数不属于公共API,那建议使用ASSERT_DEBUG()来代替。
  提示注意点
  1、如果你要排除一个指针为非空,那就建议使用一个引用来代替它。
  2、如果你要判断一个有范围的值,那建议你使用一个枚举或者T-class对象。
  3、你的构造函数可能会需要一些有关参数的预检查,这个时候最好是将这种检测放在构造函数的函数体当中。
  4、在头文件中,我们应该把函数中用到的Precondition assertions做为注释来描述出来。
  5、Preconditions不应该放在NewL()L或NewLC()中,但可以放在构造函数和ConstructL()。

——reliability (symbian)
  在函数的最后,最好是对返回值作个检查,或者函数是否完成了它应该完成的任务。可以使用ASSERT()来处理这类测试。

  提示注意点
  1、如果函数有多个返回值,那请记得给每个返回值都放上postconditions检查。
  2、如果你要判断一个返回的指针不为空,那建议你返回一个引用。
  3、同样最好把这些判断都做为注释标注起来。

——reliability (symbian)  所有的重要类都要处理invairant的检查。这些Invariants能够在类的成员函数中作为preconditions和postconditions来使用。

  Every public non-static function calls __TEST_INVARIANT at the start
and at the end (or only once if the function is a single line query). Put Invariants before preconditions and after postconditions. The last line in ConstructL() is __TEST_INVARIANT.

  注意点:
  1、如果_DbgTestInvariant()函数中调用了_TEST_INVARIANT那最好不要调用任何函数再。
2、如果函数有多个返回值那记得要在每个返回之前调用_TEST_INVARIANR!     3、You may call static functions at any time, as static member functions can't check the Invariant, not having any state to verify.


C classes
  (symbian) note C类对象不能被做为一个值来传递或者是返回,但可能通过指针或者引用来使用它。

(symbian) note Passing C class objects by pointer implies either the transfer of ownership, or that the parameter is optional. To remove this ambiguity, consider overloading functions that have optional parameters.

  (symbian) note Returning C class objects by pointer implies either the transfer of ownership, or that the return value may be NULL. To remove this ambiguity, consider pushing the object on to the cleanup stack before you return it, and adding a trailing C to the function name.

class invariants
class
viability (symbian) 在symbianOS的每个类都必须是下列五个种类之一,要使用前缀(大写字母)C, T, M, S or R。

reliability (symbian) C类必须有个析构函数,那是CBase的一个虚函数。如果是空的,那也要使用注释如//empty destructor

maintainability (c++) 尽量避免使用友类,这会破坏封装。

reusability (c++) 应该在头文件中描述所有的类,如果你要隐藏一个类,那就嵌套使用它们。

convention (nokia) 对每个类都应该有个cpp和h文件,除了嵌套类。

convention
  (symbian) note 任何从CBase中派生的类都必须有个C前缀。
  (symbian) note An M class only has virtual methods, and no data. The methods can at most have only a trivial implementation.
  (symbian) note C类对象可以推入清除栈。
  (symbian) note C class objects must either be newed, or (in rare cases) be a member variable of another C class.
  (symbian) note C classes inherit a private assignment operator from CBase, so it is not necessary for you to define one.
Coding Style
——readability
  如果你要换行,那最好在合适的地方,并且下面的行缩进。

——readability (c++)
  多使用括号来辨析含糊的地方。

——convention (nokia)
  1、主要操作附近不要有空格。
  2、不要在一元操作符和操作数之间插有空格。
  3、不要在函数名或宏名与他们的参数间插入空格。
  4、注意匹配空格和括号。

Comments
——readability
  注意不要把注意变成代码的简单复述,你应该在代码含混不清并且缺少文档的情况下使用这个注释。

——convention
  一个注释块由一个“/**”开始并且由“*/”,每行都以*开始,基本形式如下:
/**
* <BriefDescription>
* <MarkUpTag>
* <MarkUpTag>
...
* <MarkUpTag>
*/

Alternatively a shorter form can be used:
/** <BriefDescription> */

<BriefDescription>一般是一个informal, one-sentence description of the class, operation or member variable.
The <MarkUpTag> entries start with an @ sign and are the first things (after the optional leading asterisk) on the line.

——convention (nokia)
  在cpp文件代码中用//表示permanent comments。

Compilation errors
——reliability (c++)
  你可以没有编译时错误,但不可避免的要发生警告,这是因为你使用的库的原因。

Constants
——convention
  如果是常量那就要在前面加上字母K。

——convention
  常量应该被做如下的处理:
  1、在一个类中使用枚举的形式(e.g. enum { KMagicNumber = 3};,那就是说,没有类型名,并所有的在一行上)
2、类中的静态成员(e.g. static const TReal KMagicNumber;)这个只能在一个cpp文件中定义一次。Note that this only works for built-in types, and that TInt64 is not a built-in type.

Construcion
  (symbian) note C-classes 是你能new操作的唯一一个类,并且这个是他们被构造的唯一途径。
  (symbian) note All C-class member variables are nulled on creation.

Constructors
——viability (symbian) ConstructL() should never be a virtual function, since a partially constructed object isn't a polymorphic entity.

——reliability (symbian) 在C classes中的Constructors和ConstructL()必须作为保护或私有的成员函数。and should be empty apart from a member initialisation list and ASSERT macros. This enforces correct two-phase construction of object.

——reliability (symbian) 你的C class中必须有一个NewLC()函数。unless it's a nested class where you have a bit more leeway.NewL()是可选的,并且总是应该根据NewLC()来实现。两者都必须有个标准模式,应该调用ConstructL(). Non standard construction make code unclear, and prone to cleanup stack errors.

——reliability (symbian)
  在ConstructL()的实现中,你必须首先在基类中调用ConstructL()。
  (symbian) note NewL()和NewLC()在c class中必须做为静态函数,通常是公共函数。

  (symbian) note 拷贝构造函数在symbianOS总失去了它的作用,一般只有有析构函数的类才有构造函数。
consts
——reliability (c++)
Const correctness should be applied throughout. Most funcions that return a value should not change the object they are applied to.如果你有个成员变量是一个指向某对象的指针,那编译器允许你在一个const函数中调用非const函数,譬如:
Class WorstCaseScenario
  {
public:
  WorstCaseScenario() : iThis(this)
    {
    }

  void ChangeTheWorld();

  TBool InnocentLookingFunction() const
    {
    iThis->ChangeTheWorld();
    }

  WorstCaseScenario* iThis;
  }

destruction
  (symbian) note 如果一个对象被析构两次,那将是个严重的错误。在什么情况下会发生这类情况那?一般如果一个异常发生时,在清除栈中的对象和析构函数都遭到调用就会发生了。

destructors
——reliability (c++)
  在一个析构函数中或者是析构函数调用的函数中,我们并不能保证对象都被适当的构造了,因此你必须检查对象的状态并且能应付各种状况。你不必抛出任何异常。

  例如
  MyClass::~MyClass()
  {
    if(iObject) //might be NULL if constructor failed
    {
      iObject->Close();
      delete iObject;
      iObject = NULL;
    }
    delete iFred; //delete NULL is allowed
    iFred = NULL;
  }

DLLs
——viability (symbian)
  你不能在DLL中含有any global non-constant data。这包括static member variables. 你能含有的唯一全局数据就是constant static built-in types,即没有构造函数的东东:)

exceptions
——viability (symbian) note 你不能使用C++风格的异常,这个我们上面已经讲过,那个结构实现复杂很不适合symbian的小巧特性。

files
——viability (symbian)
  Place Control IDs, and defines in .hrh files.

——readability (symbian)
  在资源文件中,总是要有注释,这是为了说明文件的用法。

——convention
  .mmp和.rss文件的命名:如果只有一个,那就用project名(如animation.mmp),如果有多个的话,那就用subproject名(如engin.mmp)

——convention
  一个.mmp文件就应该有洋目录,叫做group,或者是<subproject>,里面包括.mmp.def和readme文件。

——convention
  公共头文件应该放在一个inc目录中,或者是<subproject>inc。

——convention
  所有的文档都应该在subdirectory,或是<subproject> docs。

——convention
  所有和.aif文件有关的文件都必须放在aif目录中。(To avoid name clashes with the .rss file)

——convention
  Test文件应该放在tsrc目录中或<subproject> tsrc中。

——convention
  所有其他的文件都放在src目录中或<subproject> src中。

flow control
——reliability (c++)
  Switch语句总是要有个缺省的clause,if default should never occur, the default clause should be an assertion to that effect.例如
switch(value)
{
case 0:
case 1:
case 2:
  DoSomething();
  break;
case 4:
case 5:
  DoSomethingElse();
  break;
default:
  ASSERT(EFalse);//cannot occur
}

——maintainability (c++) 永远不要用goto语句

funcionts
——maintainability (c++) 不要使用缺省参数(though exceptions can be made for having one default parameter only)。如果你的函数有n个缺省参数,那最好还是把它改为n+个该函数的重载版本。

Example:
AddControl(Control& ctrl, ControlObserver* observer = 0);

Becomes:
AddControl(Control& ctrl);
AddControl(Control& ctrl, ControlObserver* observer);

Which can be improved further to become:
AddControl(Control& ctrl);
AddControl(Control& ctrl, ControlObserver& observer);

看出来了,尽量用引用来表现参数。

——readability (c++)
  尽量保持函数体精干。

——readability (symbian)
  不要返回错误代码,使用异常机制来代替。

convention (c++)
  函数名应该由一个大写字母开始。正常Normally Midifiers are expected to do something, and hence the name is in the form of an order.
——convention (symbian) 所有的内联函数都应该放在inl文件中,记住要加关键字inline



——reliability (symbian) 注意如果函数名由一个C结尾那就表明这个函数最后返回的是个指向已放入清除栈的对象的指针。

head files
——convention
  在头文件中,要使用标准的anti-nesting 语句,这个也是一般c++的行规。
  #ifdef _CMYCLASS_
  #define _CMYCLASS_

  body of header

  #endif

注意,要使用很清楚的访问控制权限,首先列出public成员,然后是protected成员.然后是private成员。在成员函数之后列出数据成 员。在每个section中都先列出特殊的成员函数(如 NewL/NewLC/constructors/destructors/operators)。把函数按功能分类组织。把所有的overridden 函数都放在一起。还要把出处标记起来(如 //from CMyBase Class)并且不要在这里写上virtual关键字。如
//from CCoeControl
  void Draw() const;

//from MObserver
  void Notify();
  void StopObserving();

——convention (Nokia) 要使用#ifndef当要包含某个头文件在头文件中时。

#include
——convention
  首先是系统头文件(用<>来指明)然后跟着的是本地头文件(用"")

inheritance
——maintainability (c++)
  不要使用多重继承除非是为了interface(i.e mixiin classes).Interfaces不能包括成员变量。也不要什么纯虚函数。

——maintainability (c++)
  Never use private or protected inheritance.Consider whether composition would
be more appopriate.

local variables
——maintainability (c++)
  局部变量最好在使用他们的地方的附近定义最好。靠后点:)

——maintainability (c++)
  不要使用静态局部变量。

M classes
(symbian) note M类对象cannot be passed or returned by value. The choice between pointer and reference should be made according to whether a NULL value is acceptable.

macros
——reliability (c++)
  避免宏,使用enums和const static来代替#defining常量。内联函数能代替大多数使用宏的场合。注意#ifdef DEBUG是允许的就象ASSERT这个宏一样。
member variables
——reliability (c++)
It is better by far to encapsulate member data than return reference to it.如果你非得要返回一个成员变量的引用,那最好是个常量引用。如果你必须返回个非常量的引用,you need to provide both a const and a non-const (overloaded) accessor function,或者你根本不能从一个常元函数中调用。

——reliability (c++)
  无论何时你删除成员变量,你都要把他们设置为NULL,这个是个安全措施。

——maintainability (c++)
  千万不要使用公共成员变量。

operators
——viability (c++)
  Assignment operators must handle self-assignment, though this become mostly in relevant in symbian os.

parameters
——readability
  在源文件中使用与你在头文件中定义的相同参数名。

——readability (c++)
  不要使用省略符号,如 func(...)

pointers
——reliability (c++)
  不要使用指针运算。

——reliability (c++)
  不要使用指针强制转换.不幸的是有些你使用的库强制你返回某个特定值,在这种情况下要把强制转换封装在一个函数调用中,并使用c++风格的形式最好不要用c风格的(如dynamic_cast)

——reliability (c++)
  初始化所有的指针为NULL(不是0)

——reusability (symbian)
  使用descriptors 和一些特定类来代替指针,就是当你在存储数据或者处理字符串的时候。

——convention (nokia)
  如果要检查非空指针那最好通过if (ptr),而不是if (ptr != NULL)。
看出来路子不同了吧,symbian真是处处要效率呵:)

R classes
——viability (symbian)
  你不能将R-class 对象放到清除栈中,因为他们不能有析构函数。

——viability (symbian)
  你不能通过值来传递R-class对象,因为R class变量为系统资源,你不应该试图拷贝他们。

——reliability (symbian)
  R classes必须在构造函数中处理所有的成员变量初始化,you cannot rely on memebers being zeroed.

——reliability (symbian)
  R class对象不能通过new来生成。

——reliability (symbian) note
  It is generally necessary to "open" and "close" R-type objects, and hence you see code like this:

  RFile file;
  file.OpenL();
  TRAPD(err, file.ReadL());
  if(err)
  {
    file.CloseL();
    User::Leave(err);
  }
  //etc. etc

这个是很没有效率的,使得代码非常难读,being (in effect) a return to the era of checking return values for error codes. Tere is a simple method for bypassing this, shown in the following example:

  class SRClassCleanup
  {
   public:

   static void OpenLC(RFile& aFile)
   {  
    User::LeaveIfError(aFile.OpenL);
    Cleanupstack::PushL(TCleanupItem(ReleaseRFileOnCleanup, &aFile));
   }

   private:

   static void ReleaseRFileOnCleanup(TAny* aObject)
   {
    REINTERPRET_CAST(RFile*, aObject)->Close();
   }

   //repeat for all R-Classes in your project.
  };

  由此我们简化前一个列子,那取决于我们是否从SRClassCleanup派生的。
  RFile file;
  OpenLC(file);
  file->ReadL();
  //etc. etc.
  Cleanupstack::PopAndDestroy(); //close file

resource files
——convention (symbian)
  应将资源结构放在.rh文件中。

——convention (symbian)
  在资源文件中,将资源文件名写成小写。

statements
——reliability (c++)
  Never modify two different object in the same statement.

——reliability (c++)
  Break语句、多返回值和continue语句可能使你的代码更清晰,如果不能达到这个效果那你最好不要使用它们。

strings
——reusability (symbian)
  不要使用字符串常量,要用资源文件里的内容。

structs
——readability (c++)
  总是用类来取代结构。

T classes
——viability (symbian)
  因为T class对象并不能放入清除栈中,所以他不能含有析构函数,特别是当你不能确定它使用在何种环境中时。

——viability (symbian)
  T class 对象不能通过new来生成。
  (symbian) note T class对象可以做为一个值来返回或者做为引用(或值)来传递。

TBool types
  (symbian) note 编译器不允许你把TBool类型同ETrue和EFalse来比较。建议用诸如if (!Visible())来代替。

templates
——reliability (c++)
Templates should be used only for defining universal containers. Any template should be tested carefully on the target platform.

——reliability (c++)
  Templates should never be used in conjunction with virtual funcitons.

types
——viability (symbian)
  一定要使用symbianOS类型,如果用TInt来代替int

——viability (symbian)
  不要使用explicit type forms(e.g TInt16)除非在一些罕见的情况中(如从资源文件中读取资料)。

——readability (c++)
  在base types之间相互转化时,总是使用explicit casts(它将阐明你的代码含义并驱除一些警告)

——convention
  注意enumeration type的名字总是由一个大写的T前缀来开头的,而枚举的成员将是大写字母E前缀。Use relevant, meaningful, and unambiguous names for enums.

Unions
——reliability (c++)
  不要使用联合类型,除非你不得不写一些底层的面向机器代码。

variables
——reliability (c++)
  一行最好只声明一个变量。

——convention
  Put the pointer or reference indicator next to the type name, with no separating space.

——convention (symbian)
  在symbianOS中变量名常常跟着特有的前缀(如i, a, C, M, T, R, E, K, S),还可能跟着些后缀如(L, C, D),只有那些局部的变量才使用小写字母以用来distinguish them from functions.


——convention (symbian)
  变量名要尽量好懂也不要太长,当然在一个循环中使用i或j是提倡的,这些都是c/c++的风格:)

——convention (symbian)
  局部变量就要由一个小写字母开头。

——convention (symbian)
  参数名应该有前缀a,后面跟着个大写的字母。

——convention (symbian)
  成员数据名应该跟有前缀i,后面也是大写字母。

virtual funcitons
——viability (c++)
  永远不要在一个构造或析构函数中调用虚函数。原因不明而寓,可能它都没有构造好或已经解构了。

——reliability (c++)
  不要overload虚函数。

——reliability (c++)
  但你处理一个虚函数,会经常需要调用基类相关处理。譬如:
  SportsCar::DoSomething()
  {
   FastCar::DoSomething()
   //code here
  }//注意基类的调用只应该在头或尾不能是中间,这样不好维护。

——reliability (nokia)
  虚函数不要写成内联的形式,除非是析构函数。

——readability (c++)
  Never change the visibility (public/protected/private) when overriding a virtual funciton.

——reliability (c++) note
In an overridden function you cannot make any more assumptions than the preconditions of the base class implementation and your own class Invariants.