学裕 的个人资料土拨鼠照片日志列表 工具 帮助
9月14日

请小心在你的构造和析构函数调用其他函数

今天读了《Effective C++ 》,第9条原则,绝不要在构造和析构函数中调用Virtual函数,我们都知道当调用一个虚函数的时候,调用的将是被直接实例化的类或者其基类的实现,但是,如果在构造或者析构函数调用虚函数,还会遵循这种规则么?
答案是:NO
请看下面的这段代码
#include <stdio.h>

class CQBase
{
public:
    CQBase()
    {
        printLog();
    };

    virtual ~CQBase()
    {
        printLog();
    };

    virtual void printLog()
    {
        printf("CQBase\n");
    }
};

class CQDerived : public CQBase
{
public:
    CQDerived()
    {
        printLog();
    };

    virtual ~CQDerived()
    {
        printLog();
    };

    virtual void printLog()
    {
        printf("CQDerived\n");
    }
};

int main(int argc, char* argv[])
{
    CQDerived derived;
    return 0;
}

那么这段代码输出是什么呢?
答案是:
CQBase
CQDerived
CQDerived
CQBase
什么原因呢?看看那本书就知道答案,或者你在看看下面这个例子
///把CQBase类对虚函数的调用,改成间接的调用,也是错误的,所以在构造和析构函数中调用每个函数都要小心,所以最好不调用任何函数
class CQBase
{
public:
    CQBase()
    {
        init();
    };

    virtual ~CQBase()
    {
        init();
    };

    void init()
    {
        printLog();
    }
    virtual void printLog()
    {
        printf("CQBase\n");
    }
};
 再该一下,将虚函数声明为虚函数,会怎么样呢,Crash
class CQBase
{
public:
    CQBase()
    {
        init();
    };

    virtual ~CQBase()
    {
        init();
    };

    void init()
    {
        printLog();
    }
    virtual void printLog() = 0;
};