Tuesday, August 14, 2007

深入理解CBase类--6个基础问题


摘抄自


http://www.newlc.com/inside-cbase-class-six-essential-questions




如果你可以回答下面的6个问题,那么你可以不用看这篇文章了



  1. 为什么Cleanup Stack有3个不同的PushL函数?

  2. 为什么CBase有public的析构函数

  3. CBase是怎么让它的子类初始化为0的

  4. 为什么要初始化为0

  5. 为什么不建议用new[]初始化CBase的继承类

  6. 为什么CBase有private 的拷贝构造函数和private的"="重载



下面是这6个问题的答案:



  1. Cleanup Stack可以保证出现异常时被压栈的对象成功释放内存。释放内存的方法有2种,调用delete(将调用析构函数)或者调用User::Free()。对于TAny指针指向的内容,Cleanup Stack在退出时候将仅调用User::Free(),这个时候需要用PushL(TAny*)。通常的CBase对象,则调用delete,这个时候用PushL(CBase*)。如果需要压入Cleanup Stack,又不想用CBase,则使用PushL(TCleanupItem)。

  2. 因为需要被Cleanup Stack调用,所以应该是public,因为多态的需要,应该是virtual。

  3. CBase重载了new函数,调用AllocZL分配内存,自然会初始化为0

  4. 继承自CBase的类被压栈后即使出现异常也能保证析构函数被调用。那么,如果它有一个成员变量是一个指针,在析构时需要根据这个指针是否NULL判断是否需要回收这个指针指向的内存,如果这个指针没有被初始化,在运行过程中发生异常,那么析构的时候这个指针就是野指针,删除它会让程序崩溃的。看一段代码就明白了。
    CTest* CTest::NewLC()
    {
    CTest* self = new ( ELeave ) CTest;
    CleanupStack::PushL( self );
    self->ConstructL()
    return self;
    }

    void CTest::ConstructL()
    {
    iPointer = CMustLeave::NewL(); // assume this leaves
    }

    CTest::~CTest()
    {
    if( iPointer )
    {
    delete iPointer;
    iPointer = NULL;
    }
    }
    如果iPointer没有初始化为NULL,则通过Cleanup Stack析构时可能导致程序崩溃。


  5. CBase并没有重装new[],如果使用new[]创建CBase的继承类对象,CBase的new重载函数则没有被调用,自然不会初始化CBase对象为0。如果需要创建对象的数组,可以用RPointerArray。

  6. 保证不被隐式的拷贝,你不能写诸如下面的代码
    CBase* pointer = new ( ELeave ) CBase;
    CBase base = *pointer; // call copy constructor


    编译器会报错



    CBase* pointer = new ( ELeave ) CBase;
    CBase base;
    base = *pointer; // call operator =


    这样防止的不被注意的浅拷贝问题,如果需要一个深拷贝函数,可以实现一个自己的public克隆函数例如CloneL()







Technorati : ,
Del.icio.us : ,

No comments: