.3 C类
使用C前缀的类直接或间接继承自CBase类(e32base.h中定义)。
CBase有一个虚析构函数所以它的派生类对象可以通过CBase指针正确的析构。这在使用Cleanup Stack时很有用处,因为当我们Push一个CBase派生类对象时,我们实际上调用的是CCleanupStack::PushL(CBase* aPtr)。
如果一个类不是继承自CBase,那么添加到清理栈时调用的是CCleanupStack::PushL(TAny* aPtr),当CCleanupStack::PopAndDestroy()被调用时,对象内存会被释放,但不会调用其析构函数,所以如果不继承自CBase,即使类中有虚析构函数,仍然不能正确释放资源。
CBase和它的派生类的重载new操作符在分配内存时把成员初始化为0,这意味着不需要显式的构造函数,但zero-initialize对建立在栈上的对象并不适用,因为在栈上建立对象并不使用new操作符,由于这个原因,C类只能建立在堆上2渭鹐32base.h,CBase的构造函数被声明为私有,如果需要允许C类拷贝,而不是实现一个公有构造函数,应该增加一个leaving函数,例如CloneL() 或 CopyL()。
Object of a C class must always be allocated on the heap.
1.4 R类
以R为前缀的类标识了Resource,通常是一个外部资源的handle,例如与File Server的Session。没有等同的RBase,所以R类具有构造函数来设置handle为zero,来指出新建立的对象没有与resource建立关系。不应该在构造函数里初始化resource handle,因为操作可能失败;不应该在构造函数里产生leave。
为了将R类关联到resource,R类具有函数Open(), Create() or Initialize()来给资源分配空间并给成员handle赋值,当然如果失败,会返回一个错误或leave,这些类使用函数Close()或Reset()来释放资源和重置handle值,并且对同一个对象调用多次这样的函数也是安全的。理论上,清除资源的函数可以任意命名,但习惯上使用Close()。
使用R类,经常犯的错误是忘记Close(),或认为析构函数会释放资源,这可能导致memory leak.
R类一般很小,除了resource handle,一般不包含其他成员变量。R类一般(几乎)没有析构函数,因为Close()已经足够了。
R类可以作为栈类成员或局部变量,或建立在堆上,必须确保leave时,资源被释放,通常使用cleanup stack来实现。
R类的成员使用位拷贝已足够,所以没有必要定义构造函数,拷贝构造函数和赋值操作符。位拷贝的问题也许会是拷贝后导致资源所属不明确,这会导致资源被释放两次。对同一个对象调用两次Close()是安全的,因为handle值已经被重置了;但是通过两个句柄对同一对象调用两次Close()会出现问题。
如果类中包含一个位拷贝可能导致不安全的handle,应该声明一个克隆函数;如果要避免任何拷贝行为,应该声明拷贝构造函数和赋值操作符私有。
Close() must be called on an R class object to cleanup its resource.