关闭

Symbian基础知识

582人阅读 评论(0) 收藏 举报
[命名约定] 
  1、大部分类名都有一个前缀C、T、R或M,但由静态成员函数单独组成的类是没有任何前缀字母的。 

  2、结构名,结构类型可以认为是和T类很相似的,也没有外部对象,我们习惯性在结构名前加前缀T(有时可能是S) 

  3、变量名 
  *成员变量的名字由i打头(如iMember),这使得它很容易的检查一些与清除有关的规则是否执行了; 
  *参数的名字由a打头(如aControl或aIndex); 
  *局部变量的名字没有这样的前缀字母; 
  *全局变量一般是不提倡使用的,实在要用那就要以一个大写字母打头。 

  4、函数 
  *如果一个函数调用另一个可能引起异常的函数,那它的名字最好也有L后缀。 

  *和异常机制紧紧联系在一起的是清除栈,它在一个异常发生时,会恢复相应在堆上分配的内存。一个要把数据放在清除栈上的分配或构造函数应该以...LC()结尾。 

  *一个拥有对象所有权并且可以释放它的函数,应该有个...D()结尾。 
  如dialog->ExectueLD(R_BOSS_SETTINGS_DIALOG),这里的ExecuteLD()函数包括双重构造,对话框的运行以及随后的析构。 

  5、枚举名 
  名字应该有前缀T,每个枚举的成员应该有前缀E。 
  枚举的作用域应该放在相关类中 
  class TDemo 
  { 
    public: 
     enum TShape {EShapeRound, EShapeSquare}; 
  }; 
  TDemo::TShape shape = TDemo::EShapeSquare; 

  6、常量名 
  常量名应该有个K前缀。 


  [class types] 
  1、T类型 
  *大多数T类型都足够简单而不需要什么构造函数,如果要,那它的功用也就是初始化成员数据。 

*一个拷贝构造函数或是赋值操作都是很少见的,这是因为T类型的拷贝很简单,一般只是成员之间的互相拷贝,而这个正是编译器自动生成的构造函数和赋值操 作所完成的功能。当然这些函数有时候是必须的——如果T class是一个模板类,而其模板参数是个整数.如此的话,在一个TX<32>和 TX<40>之间拷贝或赋值就需要费更多的周折,那就需要好好的对一个拷贝或赋值操作来进行明确编码了。 

  *T类型没有析构函数,因为没有外部资源要被清除。 

  *T类型可以在堆栈中被很安全的释放,不需要调用什么析构函数,因为它没有外部资源要去额外处理。 

  *T类型在作为函数参数时可以通过值或引用来传递。 

  *所有的内建类型都符合T类型的标准,因此也有T前缀,如TInt 

  2、C类 
  大部分类都是C类,它们直接或间接从CBase类派生。 
  从CBase类派生的类拥有如下的特性: 
  *它们都是在堆上分配的,并且不应该是其他类的成员。 

  *在C类对象的分配中,所有的数据成员都被初始化为binary zero. 

  *它们通过指针或引用被传递,除非有明确意图,否则并不需要一个明确的拷贝构造函数或赋值操作。 

  *它们都拥有很特别的构造函数,因为异常随时可能发生,所以它们都用上了双重构造,一般的C++构造函数不适合有异常出现的情况,但是ConstructL()函数就可以处理异常发生的情况了。 

  *他们有一个虚析构函数,用来做标准的清除工作。 

  3、R类 
  R类对象拥有如下的特征: 
  *真正的对象是由另洋线程或地址空间的server所拥有的 
  *真正的对象的处理是对client不见的,既无关的。 

  下面是其关键特征: 
  *如果一个R对象打开后就必须被关闭(用open和close函数)。一般来说,如果负责打开对象的那个线程被中断了,那和该对象联系在一起的资源就被自动关闭了。 
  *他们没有明确的构造、析构或拷贝构造函数以及赋值操作。 
  *他们没有一个统一的基类。 
  *初始化函数可能有不同的名字,如Open()、Create()或Allocate()等。 
  *终止函数也有不同的名字,如Close()、Destroy()或Free()等 
  *当R类拥有外部资源时,那就有了清除的需要,这个处理是因地制宜的:) 
    

  4、M类 
  M类定义了抽象的协议或接口,其具体的处理由派生类来完成 
  M类拥有以下约束 
  *它们不应该包括任何成员数据 
  *它们不应该包括析构或构造函数,以及对=的操作重载。 
   
  M类通常包括一系列定义抽象接口的纯虚函数,有些M类可能提供成员函数的处理(尽管有上面的约束) 
  M类是symbian平台上唯一使用多重继承的类。 


[C++和机器架构] 
1、算术类型 
------ 
在大多数机器里,int是位字节,老的机器里可能是16位,新的机器则可能达到64位。 

在symbianOS中,TInt和TUint被定义为内建的int和无符号int类型,并且至少是达到32bits。 

当你需要具体尺寸时,可以使用下列几种类型: 
*TInt32/ TUint32 
32位signed 和 unsigned 整型。 

*TInt8 /TUint8 /TText8 
8-bit的signed和unsigned整型,以及8-bit character 

*TInt16 /TUint16 /TText16 
16-bit signed和unsigned整型,以及16-bit character 

*TTint64 
64-bit unsigned integer 
当ARM没有支持内建的64-bit运算时,TInt64是使用C++类的完成。 

*TReal/ TReal64 
双倍精度的浮点数,这个是推荐使用的一般浮点数类型,ARM架构并没有提供浮点的支持,你应该尽量使用整形运算(例如,大多数GUI计算),只有当程序真的需要时(如电子表格程序)才不得不使用这些浮点数类型。 

*TReal32 
32-bit浮点数,这个更小也更快,不过精度不是很另人满意的。 

2、复合类型 
-------- 

struct TEg 
{ 
  TInt iTnt; //offset 0, 4 bytes 
  TText8 iText; //offset 4, 1 byte 
  //3 wasted bytes 
  TReal iReal; //offset 8, 8 bytes 
} //total length = 16 bytes 
//都是以4 bytes = 32 bits为一个单位的 

*通常我们需要一个指向包含任何可能内容的内存的指针,在C++中我们通常用void*指针来表示,但在symbian平台中,我们用TAny* 来代替它。 

*在symbian中处理字符串的方法是descriptors。 

*参数中传递过多的数据是不明智的,事实上,任何超过2个机器字的数据都是不提倡的,因为这将引起过多的拷贝动作,相反用一个指针或引用来处理这些数据的地址要比传递数据本身好得多。 


foo(CContainer* aContainer) 
{ 
TEg s; 
TEg* ps=&s; 
aContainer->iMember=ps; 
}  
这个地方有个严重错误,就是返回了函数的局部变量,注意比较隐含 


symbian平台中堆栈上的对象的生命周期和标准C++中的非常相似,不过对其的控制有不同,如下: 

void Fool() 
{ 
  CS* s = new (ELeave) CS; //allocate and check 
  CleanupStack::PushL(s); //push, just in case 
  s->ConstructL(p1, p2); //finish constructing - might leave 
  s->UseL(p3, p4); //use - might leave 
  CleanupStack::PopAndDestroy(); //destruct, de-allocate 
} 
这里表现出四件大事情: 
(1)所有的堆分配类都是C开头的,它们都是从CBase继承来的。 
(2)使用了清除栈,以在异常发生后对象能被及时清除。 
(3)任何可能引起异常的函数都有一个L后缀。 
(4)使用new(ELeave)以防止分配空间时出现异常。 

3、Descriptors 
---------- 
*我们可以用两个类来满足字符串的基本要求:TDesC和TDes。 
TDesC是一个常量、不可更改的描述符,它有一个地址和长度。我们可以象类一样使用它,但是不能对字符串做任何修改。 
TDes是一个可以修改的描述符,和TDes比起来,它还有个最大长度,只要不超过最大的长度就可以对字符串做任意的处理。 

*描述符有个基本的特性,那就是它们不允许进行超过分配长度的字符串操作,其他类可能支持这点,如CBufBase及其派生类,因为如果TDes溢出了,就可能发生不可预料的错误。 

*描述符分几种: 
(1)指针描述符 
TPtrC只有长度和地址,因此它只需要两个机器字。 
TPtr多了一个最大的长度。 
TPtrC和TPtr有点象c中的char*指针,但由于长度已经包含在里面了,所有不需要结尾空字符。 

(2)缓冲描述符 
TBufC和TBuf包含数据在自身,就好象C中的char[] 
同样TBuf包含着一个最大长度,如TBuf<12>就是最大长度为12 
这两种描述符使用了C++的模板机制,使用了一个整形的参数指明了长度。 

*堆描述符 
HBufC将数据存放在一个堆单元中。 
这有点象C语言的(char*)malloc(length+1),同样这也是在你不得知道最终需要缓冲区大小的情况。因为缓冲描述符总是分配在堆上的,所以它们总是通过HBufC*来使用的,好过直接使用HBufC(这样避免直接使用堆地址) 

*类描述符 
如果你要描述字符数据那就使用TDes等类,如果要构建一个unicode版本,那就使用TDes16等,如果要描述字节数据,那就使用TDes8等。 

(参考图) 


[堆栈使用] 
每个线程都有一个8KB大小的堆栈,我们得小心的管理它: 
1、避免直接的值拷贝,除了基本类型 
2、在堆上生成大的对象或数组,而不要在栈上生成 
3、适当的定义变量以使他们的生命周期为最短 

[函数重载] 
如果函数拥有缺省的参数,而且如果调用者可能经常使用缺省参数来调用,那就建议重载这个函数,这是因为编译器每次都要提供一个缺省的参数,那在函数调用时就会造成多余的代码产生。 

For example, if you have 
void FunctionOne(TInt aInt=0); 

而在代码中经常这样调用它 
FunctionOne(); 

那建议定义一个 
void FunctionOne(); 
它可以这样处理 
void FunctionOne() 
{ 
  FunctionOne(0); 
} 

[内联函数] 
在以下情况使用最好: 
1、getter and setters for one- or two-machine word quantities: for example, inline ConEnv() const { return iConEnv; }; 

2、trivial constructors for T classes: 
inline TPoint::TPoint(TInt aX, TInt aY) { iX=aX; iY=aY; }; 

[Assert] 
有两个宏用来在函数中进行断言: 
  __ASSERT_ALWAYS用来捕捉运行时的非法输入,release和debug编译模式下都可以执行。 
  __ASSERT_DEBUG用来捕捉编程错误,只能用在debug编译模式下。
 
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1490360次
    • 积分:14078
    • 等级:
    • 排名:第876名
    • 原创:166篇
    • 转载:381篇
    • 译文:16篇
    • 评论:144条
    文章分类