描述符
This presentation is the property of its rightful owner.
Sponsored Links
1 / 115

描述符 PowerPoint PPT Presentation


  • 67 Views
  • Uploaded on
  • Presentation posted in: General

描述符. 第一部分. 引言. 众所周知, Symbian OS 的字符串被称为描述符 它是自描述的 描述符保存了它所表示的数据串的长度及其类型 ( 类型决定了描述符数据在内存中的实际存储情况 ) 描述符在 Symbian OS 程序员中颇有声望 重点是记住描述符的设计使其对低内存设备非常有效 使用尽量少的内存在存储字符串 , 并在长度和布局上对其进行描述. 引言. 描述符不同于标准 C++ 的字符串, Java 的字符串或者 MFC 的 CString 它们的内存分配和释放必须由程序员来管理 描述符也不同于 C 的字符串

Download Presentation

描述符

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


5083524

描述符

  • 第一部分


5083524

引言

  • 众所周知,Symbian OS 的字符串被称为描述符

    • 它是自描述的

    • 描述符保存了它所表示的数据串的长度及其类型 (类型决定了描述符数据在内存中的实际存储情况)

  • 描述符在Symbian OS 程序员中颇有声望

    • 重点是记住描述符的设计使其对低内存设备非常有效

    • 使用尽量少的内存在存储字符串,并在长度和布局上对其进行描述


5083524

引言

  • 描述符不同于标准C++的字符串,Java的字符串或者MFC的CString

    • 它们的内存分配和释放必须由程序员来管理

    • 描述符也不同于C的字符串

    • 它们防止缓冲区内存溢出并且不依赖NULL终结符来确定字符串的长度


5083524

描述符

Symbian OS 描述符的特性

  • 了解 Symbian OS的描述符可以包括文本和二进制数据

  • 了解描述符可以是窄(8位)的, 宽 (16bit)的或者为字符宽度无关的 (即16位,Symbian OS设置基于Unicode构建的)

  • 了解描述符不能自动动态的扩展它们所引用的数据区,所以如果调用某个方法使得要存储的数据大于可用空间就会导致系统错误(panic)


5083524

字符大小

  • Symbian OS

    • 被构建成支持unicode字符集,即缺省使用宽(16-bit) 字符

    • 早期的Symbian OS(EPOC)版本直到v5,其描述符都使用8位的本地字符

  • 描述符类的字符宽度可以从名称中识别出来

  • 类名以8 结尾的描述符 (例如TPtr8)使用窄 (8位) 字符串

  • 类名以16 结尾的描述符(例如TPtr16)处理16位字符串


5083524

字符大小

  • 也有一组中性类

    • 名字中没有数字 (例如TPtr)

    • 中性类通过typedef定义为平台使用的字符宽度

    • 定义中性类为了代码的兼容性,以方便在窄字符构建和宽字符构建之间进行切换

  • 现在的 Symbian OS 总是使用宽字符构建

    • 推荐的实践方法是使用中性描述符类,这样就不用显式的指定字符的宽度


5083524

内存管理

  • 描述符类不会动态管理存储其数据所用的内存空间

    • 修改方法会检查描述符的最大长度能否足够满足操作的成功

    • 如果不够,它们不会为操作重新分配内存空间

    • 而是产生系统错误以显示发生了溢出


5083524

内存管理

  • 描述符的内容可以缩小和扩展

    • 最大可以达到描述符分配的最大长度

  • 在调用描述符方法扩展数据前

    • 开发者应该进行必要的检查以确保描述符有足够的可用空间


5083524

描述符

Symbian OS 描述符类

  • 了解TDesC, TDes, TBufC, TBuf, TPtrC, TPtr, RBuf 和HBufC描述符类的特性

  • 明白基本描述符类TDesC和 TDes实现了所有一般描述符的控制代码,而派生类仅仅是添加跟它们类型相关的构造和赋值函数

  • 识别TDesC和TDes类中修改方法的正确与错误的使用

  • 意识到没有HBuf类, 但RBuf可以被用作可修改的动态分配描述符


5083524

重要描述符类概念

  • 它们将在后面介绍,但是在此之前了解以下几点是有用的

    • TDesC是所有描述符的基类

    • 目前有六个描述符派生类 (TPtrC, TPtr, TBufC, TBuf, HBufC和 RBuf)

  • 每个子类

    • 不实现自己的数据访问方法而是重载虚拟函数

    • 为了访问虚拟函数表,在每个派生描述符对象中增加4个字节以存储虚拟指针(vptr)

    • 存储描述符对象长度的4个字节中的4位用来标识描述符类的类型


5083524

重要描述符类概念

  • 描述符有两种基本结构

    • 指针描述符 –描述符拥有一个指针,该指针指向了其他某处存储字符串的地址

    • 缓冲区描述符 –字符串构成了描述符的一部分


5083524

TDesC

TPtrC

TBufCBase

TDes

TBufC<n>

HBufC

RBuf

TBufBase

TPtr

TBuf<n>

描述符类的继承层次

继承树初探


Symbian os tdesc

TDesC

TPtrC

TBufCBase

TDes

TBufC<n>

HBufC

RBuf

TBufBase

TPtr

TBuf<n>

Symbian OS 描述符类: TDesC


Symbian os tdesc1

Symbian OS 描述符类: TDesC

  • 所有描述符类从 TDesC类继承

    • 处理文字描述符 (稍后讨论)

    • 前缀 T表示是一种简单类型类

    • 后缀 C表示类是不可修改类型的描述符,比如:常量


Symbian os tdesc2

TDesC

type

iLength

0..3

4..31

4 bytes

Symbian OS 描述符类: TDesC

  • TDesC定义了每个描述符类型的基本结构

  • 为了标识每个继承类

    • 前面的4位被用来指示描述符内存结构的类型

    • 剩下的28位被用来表示描述符数据的长度

    • 描述符子最大长度是2^28 字节 (256 MB)


Symbian os tdesc3

Symbian OS 描述符类: TDesC

  • TDesC提供方法

    • 决定描述符的长度 - Length()

    • 访问数据 - Ptr()

  • 使用方法 Length()和 Ptr()

    • 基类 TDesC可以实现所有典型的针对常量字符串对象的操作, 例如数访问,比较和查找

  • 派生类型

    • 全都继承这些方法,而决不会重载,因为它们对于所有类型的描述符都是同等有效的.

    • 结果是不论描述符的类型是什么 所有的常量操作符的控制操作都由TDesC实现

      • 代码重用的好例子


Symbian os tdesc4

Symbian OS 继承类: TDesC

  • 访问描述符数据

    • 根据派生描述符类的实现(缓冲区或指针)而有所不同

    • 当描述符操作需要存储描述符数据起始部分在内存中的正确地址时

    • 可使用TDesC 的Ptr()方法,该方法将查看描述符的类型(最上面的4位)

    • 并返回起始数据的正确地址


Symbian os tdes

TDesC

TPtrC

TBufCBase

TDes

TBufC<n>

HBufC

RBuf

TBufBase

TPtr

TBuf<n>

Symbian OS 描述符类: TDes


Symbian os tdes1

TDes

TDesC

type

iLength

iMaxLength

4 bytes

4 bytes

Symbian OS 描述符类: TDes

  • 可修改描述符类都是从基类TDes中派生

    • TDesC的子类

    • TDes有额外的成员变量来保存描述符当前分配的内存所能够存储的最大数据长度

    • TDes类的MaxLength()方法返回这个值- 派生类不用重载

  • TDes定义一系列方法来操作可修改的字符串数据

    • 包括附加,填充和格式化字符串数据

    • 所有操作代码由TDes实现并被派生类所继承


5083524

派生描述符类

  • 描述符的两种基本结构:

    • 指针描述符-描述符拥有一个指针,该指针指向了其他某处存储字符串的地址

    • 缓冲区描述符-字符串是构成了描述符的一部分


Tptrc tptr

TDesC

TPtrC

TBufCBase

TDes

TBufC<n>

HBufC

RBuf

TBufBase

TPtr

TBuf<n>

指针描述符: TPtrC和 TPtr

12


Tptrc tptr1

指针描述符: TPtrC和 TPtr

  • 指针描述符的字符串数据

    • 是与描述符对象本身分离的

    • 可以存储在ROM中,堆中以及栈中

    • 存储数据的内存不被描述符所拥有

  • 指针描述符

    • 不知道它们所指向的内存实际存储在什么位置

    • 指针描述符自身通常是基于栈的

    • 但是它们可以在堆上使用,例如作为CBase派生类的成员变量


Tptrc tptr2

TPtrC

TDesC

iLength

iPtr

“hello world”

4 bytes

4 bytes

指针描述符: TPtrC和 TPtr

不可修改的指针描述符 TPtrC

  • 指向数据的数据遵循长度字,因而该描述符对象总的大小是两个字 (8 字节)

  • 在处理C中的字符串时,TPtrC等同于const char*

  • 数据可以访问但是不能修改,例如描述符中的数据是常量

  • TDesC基类定义的所有非修改性操作可以通过 TPtrC类型的对象来访问


Tptrc tptr3

指针描述符: TPtrC和 TPtr

  • 该类也定义一系列构造函数允许TPtrC能用其他对象构造:

    • 描述符

    • 指向内存的指针

    • 以空为结束符的C字符串


Tptrc tptr4

指针描述符: TPtrC和 TPtr

TPtrC构造函数实例

从一个文字描述符构造

拷贝构造自另一个TPtrC

常量缓冲区描述符

构造自TBufC

TText8是单个(8位)字符, 等同于unsigned char

构造自一个零结尾的 的C字符串

指向其他某处初始化的内存

所表示内存的长度

_LIT(KDes, "abc ....");

TPtrC ptr(KDes);

TPtrC copyPtr(ptr);

TBufC<100> constBuffer(KDes);

TPtrC myPtr(constBuffer);

const TText8* cString = (TText8*)"abc ...";

TPtrC8 anotherPtr(cString);

TUint8* memoryLocation;

TInt length;

...

TPtrC8memPtr(memoryLocation,length);


Tptrc tptr5

TPtr

TDes

TDesC

iLength

iMaxLength

iPtr

“hello world”

4 bytes

4 bytes

4 bytes

指针描述符: TPtrC和 TPtr

可修改的指针描述符 TPtr

  • 数据位置指针 (4 字节) 遵循TDes最大长度(4 字节),而最大长度又遵循TDesC的长度字(4 字节)

  • 描述符对象共三个字 (12 字节)

  • TPtr类可以访问、修改字符串和二进制数据

  • TDes 和 TDesC的所有可修改和不可修改的基类操作可以通过TPtr执行


Tptrc and tptr

指针描述符: TPtrC and TPtr

  • 类定义构造函数

    • 以允许使用指向内存地址的指针来构造TPtr类对象

    • 适当的设置长度和最大长度

  • 编译器

    • 也生成缺省的构造函数和拷贝构造函数

    • 因为在类中显式的定义成protected或者 private

  • 一个TPtr对象

    • 可以由另一个可修改的指针描述符拷贝构造

    • 例如通过调用不可修改的缓冲区类的Des()函数


Tptrc and tptr1

指针描述符: TPtrC and TPtr

TPtr构造函数例子

_LIT(KLiteralDes1, "abc ..");

TBufC<60>buf(KLiteralDes1);

TPtr ptr(buf.Des());

TInt length = ptr.Length();

TInt maxLength = ptr.MaxLength();

TUint8* memoryLocation;

...

TInt len = 12;

TInt maxLen = 32;

TPtr8 memPtr(memoryLocation, maxLen);

TPtr8 memPtr2(memoryLocation, len, maxLen);

TBufC将在后面描述,拷贝构造,可修改buf中的数据

Length=37字符

Maximumlength=60字符,

指向内存的合法指针

表示数据的长度

表示数据的最大长度

从一个指向内存的指针构造指针描述符

length=0, max=32

length=12, max=32


Tbufc tbuf

基于栈的缓冲区描述符TBufC和 TBuf

TDesC

TPtrC

TBufCBase

TDes

TBufC<n>

HBufC

RBuf

TBufBase

TPtr

TBuf<n>

12


5083524

基于栈的缓冲区描述符 TBufC和 TBuf

  • 基于栈的缓冲区描述符可以是可修改的也可以是非修改的

    • 字符串数据构成描述符对象的一部分

      • 在非修改描述符中位于长度字之后

      • 在可修改描述符中位于最大长度字之后

  • 这些描述符对大小相对固定的小字符串是有用的 (例如基于栈的字符串)

    • 可以看作等同于C中的char[]

    • 但是具有溢出检查的好处


5083524

TBufC<n>

TDesC

iLength

iBuf

“hello world”

4 bytes

n*sizeof(char)

基于栈的缓冲区描述符 TBufC和 TBuf

TBufC是不可修改的缓冲区类

  • 用来保存常量字符串或者二进制数据

  • 从TBufCBase中派生(派生于 TDesC ,主要是为了继承的方便而不能直接使用)

  • TBufC<n>是一个瘦模板类,它使用一个整型值来确定分配给缓冲区描述符对象的数据区的大小


5083524

基于栈的缓冲区描述符 TBufC和 TBuf

  • TBufC有许多构造函数

    • 一个允许非修改缓冲区从任何其他描述符的副本中构造,或者从以零结尾的字符串构造

    • TBufC可以初始创建为空,以后再填充

  • 由于数据是不可修改的

    • 缓冲区的所有内容可以通过类定义的赋值操作符来替换

    • 替代的数据可以是另一个非修改的描述符或者是以零结尾的字符串

  • 在每个例子中

    • 新的数据长度不能超过缓冲区建立时模板参数所指定的长度


5083524

基于栈的缓冲区描述符 TBufC and TBuf

TBufC构造函数实例

_LIT(KPalindrome, "aabbaa");

TBufC<50>buf1(KPalindrome);

TBufC<50> buf2(buf1);

...

TBufC<30> buf3((TText16*)"Never odd or even");

TBufC<50> buf4;

buf4 = buf1;

buf1 = buf3;

buf3 = buf2;

从文字描述符构造

从buf1构造

从零结尾的C字符串构造

构造为空length = 0

拷贝和替换

buf4包含从buf1拷贝的数据, 改变了长度

buf1包含拷贝字buf3的数据,改变了长度

Panic!Buf3的最大长度不足与存储buf2的数据


5083524

iBuf

TBuf<n>

“hello world”

4 bytes

4 bytes

n*sizeof(char)

TDes

TDesC

iLength

iMaxLength

基于栈的缓冲区描述符 TBufC和 TBuf

可修改的缓冲区数据 TBuf<n>类是瘦模板类

  • 整数值决定了缓冲区允许的最大长度

  • 从 TBufBase中派生, TBufBase从TDes中派生

  • 继承了TDes和 TDesC中所有非修改和可修改描述符操作


5083524

基于栈的缓冲区描述符 TBufC和 TBuf

  • TBuf<n>定义了一系列构造函数和赋值操作符

    • 与对应的不可修改类TBufC<n>提供的类似

_LIT(KPalindrome, "aabbaa");

TBuf<40> buf1(KPalindrome);

TBuf<40> buf2(buf1);

TBuf8<40> buf3((TText8*)"Do Geese see God?");

TBuf<40> buf4;

...

buf4 = buf2;

buf3 = (TText8*)"Murder for a jar of red rum";

从文字描述符构造

从常量缓冲区描述符构造

从零结尾的C字符串构造

构造为空

length = 0 maximum length = 40

拷贝和替换

将buf2拷贝到buf4, 更新长度

更新自C 字符串


Hbufc

TDesC

TPtrC

TBufCBase

TDes

TBufC<n>

HBufC

RBuf

TBufBase

TPtr

TBuf<n>

动态描述符: HBufC


5083524

HBuf

TDesC

iLength

iBuf

“hello world”

4 bytes

n*sizeof(char)

动态描述符: HBufC

类的结构类似于 TBufC

  • 基于堆的描述符可用于

    • 表示字符串数据,其尺寸太大不能置于栈中或者在编译时还不知道大小

    • C中使用malloc分配数据的地方


5083524

动态描述符: HBufC

  • HBufC8和 HBufC16类

    • 导出了几个静态工厂函数NewL()用以创建堆上的描述符

    • 这些函数遵循两阶段构造模型,并且在没有足够内存时异常退出

  • 没有公共构造函数

    • 所有堆缓冲区必须使用这些函数中的一个构造

  • TDesC::Alloc()或者 TDesC::AllocL()

    • 可能用到——产生已有描述符的一个HBufC类型拷贝


5083524

动态描述符: HBufC

  • 这些描述符是不可修改的

    • 与基于栈的不可修改的缓冲区描述符类一样,该类也提供了一组赋值操作符

    • 它们将替换缓冲区中的所有内容

    • 类中的对象可以通过调用Des()函数生成的指针描述符TPtr在运行时进行修改

  • 堆描述符

    • 可以根据要求的大小动态创建

    • 但是不能自动改变大小

    • 缓冲区必须有足够的内存空间来实现修改操作,否则会导致系统异常(panic)


5083524

动态描述符: HBufC

_LIT(KPalindrome, "Do Geese see God?");

TBufC<20> stackBuf(KPalindrome);

...

HBufC*heapBuf = HBufC::NewLC(20);

TInt length = heapBuf->Length();

TPtr ptr(heapBuf->Des());

ptr= stackBuf;

length = heapBuf->Length();

HBufC*heapBuf2 = stackBuf.AllocLC();

length = heapBuf2->Length();

_LIT(KPalindrome2, "Palindrome");

*heapBuf2 = KPalindrome2;

length = heapBuf2->Length();

CleanupStack::PopAndDestroy(2, heapBuf);

  • HBufC构造函数实例

    • 注意由heapBuf->Des()获得可修改的描述符 ptr

分配一个最大长度为20的堆描述符

现在length = 0

修改堆描述符

拷贝stackBuf的内容到heapBuf

length = 17

由栈缓冲区生成对缓冲区对象

length = 17

拷贝并替换heapBuf2中的数据

length = 10


5083524

TDesC

TPtrC

TBufCBase

TDes

TBufC<n>

HBufC

RBuf

TBufBase

TPtr

TBuf<n>

动态描述符: RBuf


5083524

动态描述符: RBuf

  • RBuf类的行为与HBufC类似

    • 要求的最大长度可以动态设定

    • 实例化时,RBuf对象可以分配自己拥有的缓冲区,也可以拥有预先分配的内存或者已存在的堆描述符的所有权

    • RBuf描述符通常在栈中创建

    • 但是维护一个指向堆中内存的指针

  • RBuf从 TDes类中派生

    • RBuf对象很容易修改,能传递给任何指定TDesC或者 TDes为参数的函数

    • 不需要为修改数据创建一个TPtr对象

    • 这使得当动态分配的描述符以后需要修改时,使用RBuf比HBufC更好.


5083524

‘H’

‘E’

‘H’

‘L’

‘E’

‘L’

‘L’

‘O’

‘L’

‘O’

Heap

RBuf

TDes

Union of ...

TDesC

TUint16* iEPtrType

iLength

iMaxLength

HBufC16* iEBufCPtrType

4 bytes

4 bytes

4 bytes

HBufC

动态描述符: RBuf

RBuf有两种内部表现形式:

  • 像TPtr描述符类型一样指向一个仅包含描述符数据的缓冲区

    • RBuf对象创建或者接收别处已存在内存的拥有权

  • 作为一个指向堆描述符的指针HBufC*

    • RBuf对象接收现有堆描述符的所有权,因此所指向的对象包含完全描述符对象


5083524

动态描述符: RBuf

  • 内部联合(union)表示的处理是透明的

    • 不需要知道特定的 RBuf对象在内部是如何表示

    • 描述符的操作与TDes和 TDesC的基类方法相对应

  • 类没有被命名为 HBuf

    • 因为对象不能直接在堆上创建

  • 它是R类

    • 因为它管理基于堆的资源,并负责在清除时释放内存


5083524

描述符: 第一部分

  • Symbian OS 描述符的特征

  • Symbian OS 描述符类


5083524

描述符

  • 第二部分


5083524

描述符

描述符类的继承层次

  • 了解描述符类的继承层次

  • 理解描述符类继承模型的内存有效性及其影响


5083524

TDesC

TPtrC

TBufCBase

TDes

TBufC<n>

HBufC

RBuf

TBufBase

TPtr

TBuf<n>

描述符类的继承层次


5083524

描述符类的继承层次

  • 基类 TDesC和 TDes

    • 提供了描述符操作方法

    • 为了准确的定位数据区域,必须知道它们所操作的派生类的类型

  • 每个子类

    • 没有实现自己的数据访问方法,而是进行虚函数重载

      • 这将为每个派生描述符类对象增加额外的4个字节以存储用以访问虚函数表的虚指针(vptr)


5083524

描述符类的继承层次

  • 描述符被设计成尽可能高效

    • 保存C++ vptr所用的尺寸开销被认为是不受欢迎的

  • 考虑到派生类所具有的特殊性

    • 描述符对象的存储长度4个字节的前4位被用来指示描述符类的类型


5083524

描述符类的继承层次

  • 当前有六个派生类: TPtrC, TPtr, TBufC, TBuf, HBufC和 RBuf

    • 每个类在构造时将标识位 iType设置成适当的值

    • 使用4 位来标识类型限制了不同类型描述符的数目最多为2^4 (= 16)

    • 似乎这个范围将来不需要进行很大的扩展


5083524

描述符类的继承层次

  • 对于所有描述符, 访问描述符数据都是通过基类TDesC 的非虚函数Ptr()

    • 它使用switch 语句状态检查4位,标识描述符类型,然后返回其数据开始的正确位置.

    • 这就要求基类TDesC知道其子类的内存结构,并将其硬编码到Ptr()中


5083524

描述符

使用描述符 APIs

  • 了解描述符基类TDesC和 TDes不能实例化

  • 理解描述符方法Size(), Length()和 MaxLength()的区别

  • 理解描述符方法 Copy()和 Set()的区别并且知道如何使用正确赋值函数


5083524

使用描述符 APIs

  • 描述符基类 TDesC和 TDes

    • 提供和实现了所有描述符操作的API

    • 典型的, 派生描述符仅实现构造和拷贝赋值的特定方法.

  • TDesC和 TDes类型的对象

    • 由于缺省构造函数是保护类型所以不能直接实例化

    • 实际实例化和使用的都是派生描述符

  • 描述符API函数

    • 在每个SDK的Symbian OS文库中都有全面的文档以及课程例子

    • 本讲座主要关注描述符操作的一些技巧


5083524

使用描述符 APIs

  • Length()和 Size()之间的区别

    • Size()函数返回以字节为单位的描述符大小

    • Length()函数返回它所包含的字符数目

    • 对于8位描述符,它们的是一样的,因为一个字符的大小就是一个字节

  • Symbian OS v5u (第5版unicode版)

    • 系统字符是16位的,即每个字符占用两个字节

    • 对于中性描述符和显式声明的宽描述符,Size()返回的值总是 Length()返回值的两倍


Maxlength

MaxLength()和长度修改函数

  • MaxLength()函数

    • TDes的MaxLength()函数返回可修改描述符的最大长度

    • 象 TDesC的Length()函数,它不能被派生类重载

  • SetMax()函数

    • 设置描述符当前长度到允许的最大长度

    • 不能通过改变描述符的最大长度从而扩展或者缩小数据区


Maxlength1

MaxLength()和长度修改函数

  • SetLength()函数

    • 可用于调整字符串长度到0和最大长度之间的任何值

  • Zero()函数

    • 设置长度为0


5083524

Set()和赋值操作符

  • 指针描述符类型

    • 提供Set()函数使其指向不同的字符串数据

_LIT(KDes1, "Sixty zippers were quickly picked from the woven jute bag");

_LIT(KDes2, "Waltz, bad nymph, for quick jigs vex");

TPtrC alpha(KDes1);

TPtrC beta(KDes2);

alpha.Set(KDes2); // alpha points to the data in KDes2

beta.Set(KDes1); // beta points to the data in KDes1

Literal descriptors are described later


5083524

Set()和赋值操作符

  • TDes提供赋值操作符 TDes::operator =()

    • 用于将数据拷贝到任何可修改描述符的内存中

    • 倘若要复制的数据长度不超过描述符的最大长度,否则会引发一个致命错误(panic)

  • 容易混淆 Set()和 TDes::operator =()

    • Set()重置指针描述符指向新数据区

      • 改变长度和最大长度成员变量

    • TDes::operator =()仅复制数据到现有的描述符

      • 修改描述符长度但是不修改最大长度


5083524

Set()和操作符 =()

_LIT(KLiteralDes1, "Jackdaws love ...");

TBufC<60> buf(KLiteralDes1);

TPtr ptr(buf.Des());

TUint16* memoryLocation;

...

TInt maxLen = 40;

TPtr memPtr(memoryLocation, maxLen);

memPtr = ptr;// 赋值

_LIT(KLiteralDes2, "The quick brown fox ...");

TBufC<100> buf2(KLiteralDes2);

TPtr ptr2(buf2.Des());

ptr.Set(ptr2);

memPtr =ptr2;

指向 buf的内容

指向内存的合法指针

...

最大长度设置max length=40

拷贝和替换

memPtr的数据是KLiteralDes1 (37 字节),

max length=40

指向buf2的数据

替换ptr所指向的内容

ptr指向buf2的内容, max length = 100

尝试更新 memPtr, 将发生致命错误因为

ptr2的内容 (43 字节) 超过了

memPtr的最大长度(40 字节)


5083524

使用 Des()修改数据

  • 非修改缓冲区描述符的内容不能直接修改除非进行全部替换

    • 基于栈和堆的描述符TBufC和 HBufC提供一个可以返回可修改指针描述符的方法,该指针指向缓冲区描述符的数据

  • 但是可能间接改变数据

    • 调用 Des()获得可修改指针描述符,然后通过该指针操作数据

  • 当数据通过Des()返回值进行修改时

    • 指针描述符和常量缓冲区描述符的length成员变量都会更新


5083524

使用 Des()修改数据

注意: 所有描述符 都是8位

从文字描述构造

数据是buf中的字符串, max length = 40

利用 ptr替换buf的内容

致命错误!

KPal2超出了buf 的最大长度限制 (=40)

_LIT8(KPalindrome, "Satan, oscillate...");

TBufC8<40> buf(KPalindrome);

TPtr8 ptr(buf.Des());

...

ptr = (TText8*)"Do Geese see God?";

ASSERT(ptr.Length()==buf.Length());

_LIT8(KPal2, "Are we not drawn onward...");

ptr = KPal2; // 赋值


5083524

描述符

描述符作为函数参数

  • 理解无论是常量数据和可由函数修改的数据,指定描述符作为函数参数的正确方法是使用引用


5083524

操作符作为函数参数

  • 描述符基类 TDesC和 TDes

    • 为所有描述符操作提供和实现APIs

    • 可以作为函数参数和返回值,允许描述符被传入代码而不必强制依赖特定的类型

  • API 客户端

    • Should not be constrained to using a TBuf because a particular function requires it

    • 不应因为特定的函数需要它仅限于使用TBuf

  • 函数提供者

    • 应当保留对传入的描述符类型的无知

  • 除非函数接收或者返回拥有权

    • 不需指定描述符是基于栈的还是基于对的


5083524

操作符作为函数参数

  • 当定义函数时

    • 基类TDesC和TDes应当总被用作参数或返回值

    • 为效率计,描述符参数应当以引用的方式传递

    • 对常量描述符使用constTDesC& 或者需要修改时使用 TDes&

  • 例外:当将基于堆的描述符的拥有权作为返回值时

    • 需要明确指出,这样调用者才能适当得清楚它以避免内存泄露


5083524

描述符

动态描述符类的正确使用

  • 识别正确技术和方法来初始化一个HBufC堆缓冲区对象

  • 明白和验证如何使用新描述符类RBuf


5083524

动态描述符类的正确使用

  • HBufC构造和使用

    • HBufC可以通过使用TDesC 实现的重载方法Alloc()或者AllocL()从现有的描述符中生成

    • 实例显示怎样使用DesC::AllocL()取代低效代码

void CSampleClass::UnnecessaryCodeL(const TDesC& aDes)

{

iHeapBuffer = HBufC::NewL(aDes.Length());

TPtr ptr(iHeapBuffer->Des());

ptr.Copy(aDes);

...

}

可以被替换成一行语句

{

iHeapBuffer = aDes.AllocL();

}


Hbufc1

HBufC构造和使用

  • HBufC对象

    • 也可以用该类的静态工厂方法static NewL()进行实例化

    • 对于HBufC16,可以使用如下方法:

static IMPORT_C HBufC16* NewL(TInt aMaxLength);

static IMPORT_C HBufC16* NewLC(TInt aMaxLength);

  • 这些方法用指定的最大长度创建一个新的基于堆的缓冲区描述符

  • 如果没有足够的内存进行分配则异常退出

  • NewLC方法将成功创建的描述符对象保留在清除栈上

    堆描述符为空,并且长度被设置为0


5083524

HBufC构造和使用

  • HBufC16对象

    • 也可以使用非异常退出函数static New()进行实例化:

static IMPORT_C HBufC16* New(TInt aMaxLength);

  • 该函数用指定的最大长度创建新的基于堆缓冲区描述符

  • 如果没有可用的堆内存分配给描述符,它不会异常退出

  • 调用者必须比较返回的指针是否是NULL以便在提领(dereference)它前来确认是否分配成功

  • 堆描述符为空,并且长度设置为0


5083524

HBufC构造和使用

  • NewMax方法也设置 HBufC16 的长度为最大值

static IMPORT_C HBufC16* NewMax(TInt aMaxLength);

static IMPORT_C HBufC16* NewMaxL(TInt aMaxLength);

static IMPORT_C HBufC16* NewMaxLC(TInt aMaxLength);

  • 这些函数用指定的最大长度创建一个新的基于堆的缓冲区描述符并且设置长度到最大值

  • 没有给描述符数据赋值

  • 如果有足够的内存供分配:

  • NewMax()返回 NULL指针 ()

  • NewMaxL()和 NewMaxLC()将会异常退出

    NewMaxLC()将成功分配的描述符遗留在清除栈上


5083524

HBufC构造和使用

  • 从RReadStream 内容初始化HBufC16

static IMPORT_C HBufC16* NewL(RReadStream& aStream, TInt aMaxLength);

static IMPORT_C HBufC16* NewLC(RReadStream& aStream, TInt aMaxLength);

  • 这些方法分配基于堆的缓冲区描述符并且用读入流的内容对其进行初始化

  • 从读入流读入数据直到指定的最大长度 (或者流数据的最大长度 – 二者中最短的) 并且分配缓冲区保存该内容

  • 典型的用于重构以前被流操作外部化到一个写入流的描述符


5083524

描述符的外部化和内部化

将iHeapBuffer内容写入到一个可写流

写入描述符的长度

写入描述符的内容

用读入流的内容实例化iHeapBuffer

读入描述符的长度

分配iHeapBuffer

在iHeapBuffer上创建一个可修改描述符

用ptr 将描述符数据读入iHeapBuffer

void CSampleClass::ExternalizeL(RWriteStream& aStream) const

{

aStream.WriteUint32L(iHeapBuffer->Length());

aStream.WriteL(*iHeapBuffer, iHeapBuffer->Length());

}

/** */

void CSomeClass::InternalizeL(RReadStream& aStream)

{

TInt size = aStream.ReadUint32L();

iHeapBuffer = HBufC::NewL(size);

TPtr ptr(iHeapBuffer->Des());

aStream.ReadL(ptr,size);

}

  • 描述符使用流外部化和内部化例子


5083524

描述符的外部化和内部化

  • 下面的代码

    • 显示使用流操作符作为一种更有效的选择

    • 流操作符已经被优化来尽可能的压缩描述符的元数据,这急能提高效率也能节省空间

void CSampleClass::ExternalizeL(RWriteStream& aStream) const

{// Much more efficient, no wasted storage space

aStream << iHeapBuffer;

}

void CSampleClass::InternalizeL(RReadStream& aStream)

{// KMaxLength indicates the maximum length of

// data to be read from the stream

iHeapBuffer = HBufC::NewL(aStream, KMaxLength);

}


5083524

RBuf

  • 虽然有非修改堆描述符类HBufC

    • 但没有相应地可修改类 HBuf

      • 这可能为很多开发者所期待,以便能够使堆缓冲区与栈缓冲区类TBuf对称

  • RBuf类首先在 Symbian OS v8.0 中引入

    • 但是在Symbian OS v8.1 中才第一次有文档介绍,并在Symbian OS v9 和以后版本的手机软件设计中广泛应用


5083524

RBuf构造和使用

  • RBuf对象可以按照以下方式进行实例化

  • 用Create(), CreateMax()或者CreateL()指定能存储的描述符数据的最大长度

  • 也可以存储另一个描述符内容的拷贝对RBuf进行实例化:

  • Create()分配一个缓冲区为RBuf所引用

  • 如果RBuf以前拥有缓冲区, Create()将不会在设置新的缓冲区引用之前清除它

    • 必须首先调用Close()进行显式清除

  • RBuf也可以使用Assign()方法拥有以前存在的内存段的拥有权

    • Assign()也会使已拥有的数据成为孤儿

      • (应当首先调用Close()防止内存泄漏)

  • RBuf myRBuf;

    _LIT(KHelloRBuf, "Hello RBuf!");

    myRBuf.Create(KHelloRBuf());


    5083524

    RBuf构造和使用

    • 使用 Assign()得到拥有权

    得到HBufC的拥有权

    使用与清除

    获得以前分配的堆内存的所有权

    使用与清除

    HBufC* myHBufC = HBufC::NewL(20);

    RBuf myRBuf;

    myRBuf.Assign(myHBufC);

    ...

    myRBuf.Close();

    TInt maxSizeOfData = 20;

    RBuf myRBuf;

    TUint16* pointer =

    static_cast<TUint16*>(User::AllocL(maxSizeOfData*2));

    myRBuf.Assign(pointer, maxSizeOfData);

    ...

    myRBuf.Close();


    5083524

    RBuf构造和使用

    • RBuf类

      • 不管理缓冲区的长度并且在需要更多内存时会重新分配

      • 如果在RBuf 对象上调用Append()却没有足够的可用内存——则会产生一个致命错误

      • 从基类方法是非异常退出的事实很容易了解这一点


    5083524

    RBuf构造和使用

    • RBuf操作的内存必须由程序员管理

      • ReAllocL()函数可以按如下方式使用:

    myRBuf是要重置大小的缓冲区 例如. 通过Append()操作

    推入清除栈中以保证异常退出安全

    扩展到newLength

    从清除栈移除

    myRBuf.CleanupClosePushL();

    myRBuf.ReAllocL(newLength);

    CleanupStack::Pop ();


    5083524

    RBuf构造和使用

    • 使用RBuf 优于HBufC ,因为:

      • 如果在HBufC对象上调用ReAllocL()方法会造成堆单元的移动,并且需要更新关联的HBufC*和TPtr 变量

      • 这种更新对于RBuf对象是不需要的,因为当它的指针是内部维护的


    5083524

    RBuf构造和使用

    • 类没有被命名为 HBuf

      • 它们不像 HBufC对象是自身是直接在堆上创建的

    • 而是R类

      • 因为它管理基于堆的资源并负责在清除时释放内存

        • 对其他R类来说通常是调用Close()执行清除

    • 如果 RBuf

      • 通过调用CleanupClosePushL()被压入清除栈,要使用CleanupStack::PopAndDestroy() 来清楚它


    5083524

    RBuf构造和使用

    • 可以从现有的HBufC 创建RBuf

      • RBuf类是既可修改也可以动态申请,因此要优于HBufC

      • 能够从HBufC 对象创建RBuf对于Symbian OS v8.1 以前的程序而言是一个很好的移植方法

    • 以前

      • 需要实例化HBufC, 然后使用关联对象TPtr——通过调用堆描述符的Des()方法创建

    • 何时使用 RBuf或者 HBufC?

      • 当要求动态分配的缓冲区并且保存的数据是频繁改变的,推荐RBuf

      • 当要求动态分配的描述符而其保存很少变化,则推荐HBufC


    5083524

    HBufC和RBuf

    使用RBuf修改数据

    使用HBufC修改数据

    HBufC* socketName = NULL;

    // KMaxNameLength 在其他地方定义

    if(!socketName)

    {

    socketName = HBufC::NewL(KMaxNameLength);

    }

    // 创建科协的同伴TPtr

    TPtr socketNamePtr(socketName->Des());

    message.ReadL(message.Ptr0(), socketNamePtr);

    RBuf socketName;

    ...

    if(socketName.Compare(KNullDesC)==0)

    {

    socketName.CreateL(KMaxNameLength);

    }

    message.ReadL(message.Ptr0(), socketName);

    代码很简单 – 方便理解和维护


    5083524

    描述符

    描述符使用中的常见低效用法

    • 知道TFileName对象不应不加选择的随意使用,因为其所耗用的占空间

    • 理解何时直接提领一个HBufC对象,何时调用Des()获得一个可修改描述符(TDes&)


    5083524

    描述符使用中的常见低效用法

    • TFileName对象浪费栈空间

      • TFileName 类型被typedef为一个最大长度为256字符的可修改栈缓冲区

      • 当调用各种文件系统函数来将文件名解析成完整路径时是很有用的——因为文件名的确切长度在编译时是知道的

      • 例如打印一个目录的内容

    • 但是,由于每个字符都是16位宽

      • 每次在栈上声明一个TFileName对象,它就会消耗2 × 256 = 512个字节

      • 还有描述符对象自己使用的12个字节

      • 那已经超过0.5 KB!

        • 一个应用程序的缺省栈大小只有8KB


    Tfilename

    TFileName对象浪费栈空间

    • 在Symbian OS中,每个进程的栈空间是有限的

      • 缺省只有8 KB

      • 在Windows模拟器中,如果还需要更多的栈空间,它将会自己扩展

      • 但是在手机上并不是这样——栈溢出时将引发一个致命错误

      • 这很难进行跟踪,因为在模拟器上不会有这种错误所以不能很容易的调试出来


    Tfilename1

    TFileName对象浪费堆空间

    • 一个TFileName对象消耗0.5KB

      • 会消耗,并且潜在的浪费,栈空间的很大一部分

    • 使用动态堆描述符类型是种良好的习惯

      • 或者将TFileName对象的使用限制在C类成员上,因为它们是在堆上创建的


    Tdesc hbufc

    通过TDesC引用 HBufC

    • HBufC类从 TDesC中派生

      • HBufC*指针可被简单的提领,当要求一个指向非修改描述的引用时

    • 调用堆描述符Des()方法的一个常见错误

      • 它将创建一个独立的指向描述符数据的TPtr

      • 返回TDes&是没问题的

      • 但是更加清晰有效的是直接HBufC对象

    const TDesC& CSampleClass::AccidentalComplexity()

    {

    return (iHeapBuffer->Des());

    // 可以替换成更加有效的

    return (*iHeapBuffer);

    }


    5083524

    描述符

    文字描述符

    • 知道如何操作文字描述符以及知道那些用L宏定义的已经被废弃了

    • 明白使用_L和_LIT文字描述符的差别以及和使用前者的缺点


    5083524

    文字描述符

    • 文字描述符不同于其他类型的描述符类型

      • 它们与C中的static char[]是等同的,可以内建到ROM中的程序二进制代码中(如果代码是系统的一部分的话),因为它们是常量

      • e32def.h定义一组宏,它们被用来定义两种不同的Symbian OS 文字描述符, _LIT和 _


    5083524

    文字描述符

    • _LIT宏

      • Symbian OS 优先使用_LIT宏,因为它是更高效的类型

      • 它的使用贯穿了本讲座,典型的如下所示:

    _LIT(KFieldMarshalTait, "Field Marshal Tait");

    • KFieldMarshalTait便可以被用作常量描述符- 例如写到文件中或者显示给用户


    5083524

    _LIT宏

    • _LIT宏

      • 构建一个TLitC16类型的命名对象(KFieldMarshalTait) 到程序的二进制代码中

      • 在本例中保存的是字符串"Field Marshal Tait“

      • 显式宏_LIT8和_LIT16的行为方式相似,除了LIT8构建的是一个TLitC8类型的窄字符串


    5083524

    _LIT宏

    • TLitC8和 TLitC16不是从 TDesC8或者TDesC16中派生

      • 但是它们和 TBufC8或者TBufC16 有相同的二进制结构

      • 这使得这些类型的对象能够用于任何TDesC 使用的地方

      • 存储在程序二进制中的字符串用NULL指针结束,因为使用本地编译器的字符串来构建它

      • _LIT宏为非结束描述符(non-terminated descriptor)将长度调整到正确值


    5083524

    _LIT宏

    • Symbian OS 也定义了表示空串的文字类

      • 有三种空描述符变体,定义如下:

      • 构建无关的(Build independent):

      • 8位非Unicode字符串:

      • 16位Unicode字符串:

    _LIT(KNULLDesC,"");

    _LIT8(KNULLDesC8,"");

    _LIT16(KNULLDesC16,"");


    5083524

    _L宏

    • 使用 _L 宏

      • 现在在产品代码中已经被废弃了

      • 可能仍然在测试代码中使用(那里内存的使用不是那么关键)

      • 使用_L的好处是不用在使用之外单独声明,而是直接代替TPtrC

    User::Panic(_L("telephony.dll"), KErrNotSupported);

    • 上面的例子, 字符串 (“telephony.dll”) 作为一个基本的零结尾的字符串被构建到程序的二进制代码中


    5083524

    _L宏

    • 不像_LIT宏构建的 TLitC

      • 没有初始的长度成员

      • 这意味着存储文字的内存布局不像描述符的,例如没有length字

    • 于是在代码执行时

      • _L的每个实例会导致构建一个临时的TPtrC

      • 其指针被设置为指向文字的第一个字节,因为它是存储在ROM中的


    Lit l

    12

    Hello World!\0

    _LIT 和 _L 内存布局

    • 不同内存布局

      • 使用_LIT和_L宏来创建ROM中文字

    _LIT(KHello,”Hello World!”)

    TPtrC KHello(_L(”Hello World!”))

    ROM

    临时栈变量

    ROM

    iLength 12

    iPtr

    Hello World!\0


    5083524

    描述符

    描述符转换

    • 了解如何使用描述符Copy()函数或CnvUtfConverter 类将8位描述符转换成16位描述符,以及将16位转换为8位

    • 知道如何将文件中的数据读到8位描述符中并在填充的情况下将其转成16位的,以及将16位转成8位

    • 知道如何用TLex类将描述符转换成数字, 已经用函数TDes::Num() 将数字换成为描述符


    5083524

    描述符转换

    • 在宽和窄描述符之间转换

      • TDes实现一组Copy()重载函数,它们允许从下面几处直接复制数据到描述符:

        • 另一个描述符

        • 以空结尾的字符串

        • 指针

    • Copy()方法

      • 将数据复制到描述符并设置相应的长度

      • 如果用来接收的描述符的最大长度比引入的数据长度小则函数会引发致命错误


    5083524

    描述符转换

    • Copy()函数

      • 被重载成接受8位或者16位描述符

    • 可以

      • 将窄描述符复制到窄描述符

      • 将宽描述符复制到宽描述符

    • 也可以

      • 在不同宽度描述符之间进行复制

      • 例如在进程中执行隐含转换


    5083524

    将宽描述符转化成窄描述符

    • TDes8实现的Copy()函数

      • 可以将输入的宽描述符复制到窄描述符

      • 假定交替字符位0而将其剔除–数据值不能扩展到 255 (decimal).

      • 将窄描述符复制到数据区域的Copy()函数是直接的数据拷贝

    C

    A

    T

    TBuf8<3> cat(_L8("CAT"));

    TBuf16<3> dog(_L16("DOG"));

    cat.Copy(dog);

    D

    \0

    O

    \0

    G

    \0

    在宽到窄的描述符拷贝中NULL字符被剥除

    D

    O

    G


    5083524

    S

    L

    S

    M

    \0

    \0

    A

    A

    M

    L

    \0

    \0

    L

    R

    A

    \0

    \0

    L

    G

    \0

    \0

    L

    E

    \0

    \0

    窄描述符转换成宽描述符

    • 对于类 TDes16

      • 输入的16位描述符可以直接复制到数据区域

      • Copy() 函数接收8位描述符时,在复制操作中在每个字符后面填充一个0

    TBuf8<5> small(_L8("SMALL"));

    TBuf16<5> large(_L16("LARGE"));

    large.Copy(small);

     用NULL字符来填充窄到宽转换的描述符


    5083524

    Copy()函数

    • Copy()函数

      • 构成了复制以及在 8位和16位描述符中转换的根本方法

      • 当字符集被编码成每个字符一个字节

      • 以及每个宽字符的后一个字节都进行简单的0填充时


    Cnvutfconverter

    CnvUtfConverter类

    • 用来执行正确的转换

      • 16位Unicode (UCS-2) 和8位非Unicode 字符集合之间双向转换

      • 或者在Unicode 和 UTF-7 和 UTF-8 转换集合之间转换

    • CnvUtfConverter类

      • 由 charconv.lib (头文件 utf.h) 提供

      • 改了类提供一组静态函数,例如ConvertFromUnicodeToUtf8()和ConvertToUnicodeFromUtf8()


    5083524

    将数目转换为描述符

    • 描述符可以用TLex 类转换成数字

      • 该类提供通用的词法分析,能进行句法元素的解析以及字符串到数字的转换

      • 使用TChar 的低于依赖函数来决定每个字符是数字,字符还是符号


    5083524

    将数目转换为描述符

    • TLex是构建宽度中立的类

      • 隐含的是TLex16

      • TLex8和 TLex16也可以显式的使用

      • 除非要求使用特定的变量,中性形式是首选

      • TLex可以用数据构造,或者先以空数据构造然后设置数据

      • 构造和赋值都可以接受(作为参数)

        • 另一个 TLex对象

        • 一个非修改描述符

        • 指向字符串数据的TUint16*或者TUint8*指针(分别对应 TLex16或者 TLex8)


    5083524

    将描述符转换为数字

    • 最简单层次

      • 当字符串只包含数值数据,可以使用TLex 的Val()函数将描述符内容转换成整数

    _LIT(KTestLex, "54321");

    TLex lex(KTestLex());

    TInt value = 0;

    TInt err = lex.Val(value); // 如果没有错误发生,value 等于 54321

    • Val()函数针对不同的符号整型以及有无范围检查进行了重载

    • 也有针对无符号整型的Val()重载函数,它们需要传入一个基数(10,16,2或者8);TRealTLex还提供了几个其他API方法进行操作和解析

      这些在每个SDK的Symbian OS Library中都有文档介绍


    5083524

    将数目转换为描述符

    • 描述符类

      • 提供许多方法将数目转换成描述符

      • AppendNum(), AppendNumFixedWidth(),Num()和 NumFixedWidth()的不同重载方法将特定数目的参数转换成字符表示

      • 或者完全取代原来的内容或者添加数据到描述符


    5083524

    将数目转换为描述符

    • 用转换指令(conversion directives)进行格式化

      • TDes的Format(), AppendFormat(),FormatList()和AppendFormatList()方法每一个都接收一个格式化字符串参数

      • 包含了嵌入在格式化指令的文字

      • 以及一堆参数

    • 每个格式化指示

      • 使用参数列表中的一个或多个参数

      • 并用于将数字转换成描述符数据


    5083524

    在描述符中包裹对象

    • 平(Flat) 数据对象

      • 能够用包缓冲区(package buffer) TPckgBuf类和包指针(package pointer) TPckg及TPckgC类存储在描述符中,

      • 这对发送客户端-服务器请求时的线程间和进程间数据传输十分有用

    • T类对象

      • 可以整个的包裹进一个描述符(”描述符化的”),这样它就能在线程或进程间以类型安全的方式进行传递


    5083524

    在描述符中包裹对象

    • TPckgBuf, TPckg 和TPckgC类型

      • 是瘦模板类

      • 分别派生于TBuf<n>, TPtr和 TPtrC (见e32std.h)

      • 这些类是类型安全的并且对要包裹的类进行了模板化


    5083524

    在描述符中包裹对象

    • 有两个包裹指针类

      • 可修改 TPckg或者不可修改 TPckgC指针描述符 指向了模板包裹了的类(template-packaged class)的一个已存在的实例

      • 可以调用附加对象的方法 (后面幻灯片中的TSample theSample)

      • 如果它被附加到一个TPckgC中,其operator()方法将返回一个被包裹类的常量引用


    5083524

    在描述符中包裹对象

    • 有一个包裹缓冲区类

      • 包缓冲区 TPckgBuf创建并且存储封装在描述符中的类的一个新实例

      • 复制的对象由包裹缓冲区所拥有 (下一个幻灯片)

    • 它是可修改的

      • 调用TPckgBuf对象operator()可以找后包裹的对象,然后就可以调用该类的方法

      • 包裹缓冲区包含初始对象的副本,因此修改的是副本,初始对象并没有变化


    Tpckg tpckgc tpckgbuf

    TPckg<TSample>

    TBuf<n>

    TPtrC

    TPtr

    TDes

    TDesC

    TDes

    TDesC

    iLength

    iPtr

    TDesC

    iLength

    iMaxLength

    copy of theSample

    iLength

    iMaxLength

    iPtr

    TSample theSample

    TPckgC<TSample>

    TPckBuf<TSample>

    TPckg,TPckgC 和 TPckgBuf类的内存结构


    5083524

    在描述符中包裹对象

    TSample 是要包裹在描述符包裹类中的类

    可以在附加对象上调用的方法

    包含theSample的可修改包裹

    包含theSample的不可修改包裹

    包含theSample副本的可修改包裹

    直接调用附加对象theSample的方法

    变异错误!非常量方法

    调用一个常量方法是可以的

    修改theSample的副本

    class TSample

    {

    public:

    void SampleFunction();

    void ConstantSampleFunction() const;

    private:

    TInt iSampleData;

    };

    TSample theSample;

    TPckg<TSample> packagePtr(theSample);

    TPckgC<TSample> packagePtrC(theSample);

    TPckgBuf<TSample> packageBuf(theSample);

    packagePtr().SampleFunction();

    packagePtrC().SampleFunction();

    packagePtrC().ConstantSampleFunction();

    packageBuf().SampleFunction();

    • 封装在每种包过类型中的简单T 类


    5083524

    描述符: 第二部分

    • 描述符类的继承层次

    • 使用描述符APIs

    • 描述符作为函数参数

    • 动态描述符类的正确使用

    • 描述符使用中的常见低效用法

    • 文字描述符

    • 描述符转换


  • Login