条款9:绝不在构造函数和析构函数中调用virtual 函数

来源:互联网 发布:大连pmp培训 知乎 编辑:程序博客网 时间:2024/05/21 11:26
条款9:绝不在构造函数和析构函数中调用virtual 函数

1、在构造函数中调用virtual 函数

 先看段代码,书中的例子,修改了下
class Transaction{public:Transaction() {LogTransaction();}virtual void LogTransaction(){cout<<"Trasaction Log \n";}};class BuyTransaction : public Transaction{public:void LogTransaction() {cout<<"BuyTransaction Log \n";}};
调用
BuyTransaction b;
结果
Trasaction Log

    通过结果可以看出不是我们想要的。BuyTransaction b,这里BuyTransaction 构造函数会被调用,但会先调用基类Trasaction的构造函数,但该构造函数里面调用一个virtual 函数,意向是调用子类的LogTransaction函数,但实际上子类还没有开始构造,即对象还没有在内存中形成,对象的所有成员还没有定义,因此编译器不会让这样不可意料的事情发生,规定:base class构造期间virtual函数绝对不会下降到derived class型阶层,即在该阶段对象时隶属base class的,调用的virtual 函数不是virtual 函数。
    在书中还有另一种说法,在derived class对象的base class构造期间,对象的类型是base class而不是derived class。不只virtual函数会被编译器解析至(resolve to)base class,若使用运行期类型信息,也会把对象视为base class类型。因为“derived 专属成分”尚未初始化,因此:对象在derived class构造函数开始执行前不会成为一个derived class对象。

2、在析构函数中调用virtual 函数

    其结果和解释都可以跟上面一样,基类的析构函数中调用virtual 函数,结果还是调用基类的函数,因为析构函数的行为时:先调用子类的析构函数,再到基类,子类析构后,子类的所有成员均为未初始化,因此,进入基类的析构函数后对象就成为一个基类对象。

如何解决上面的问题呢?将virtual 函数修改为non-virtual 函数,在子类中构造函数中传入对应的值。
class Transaction{public:Transaction(const std::string &strLog) {LogTransaction(strLog);}void LogTransaction(const std::string &strLog){cout<<"Trasaction Log :"<<strLog<<endl;}};class BuyTransaction : public Transaction{public:BuyTransaction(const std::string &strLog) : Transaction(strLog){}};

记住
在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造和析构函数的那层)。



     
0 0
原创粉丝点击