Effective C++学记之09 绝不在构造和析构过程中调用virtual函数

来源:互联网 发布:subtitle软件 编辑:程序博客网 时间:2024/05/16 15:05
在构造和析构期间不要调用virtual函数,因为这类调用从不下降至子类。

例:股票交易买进卖出审计日志系统。
class Transaction{
public:
    Transaction();
    virtual void logTransaction() const = 0; //做出一份因类型不同而不同的日志记录
    ...
};
Transaction::Transaction()
{
    ...
    logTransaction(); // 志记交易
}

class BuyTransaction:public Transaction{
public:
    virtual void logTransaction() const  //志记此型交易
    ...
};
class SellTransaction:public Transaction{
public:
    virtual void logTransaction() const  //志记此型交易
    ...
};

当BuyTransaction b;被执行时:
首先调用父类的构造函数。在构造函数中调用的virtual函数是父类的版本,绝不是子类的版本!
父类构造期间virtual函数绝不会下降到子类阶层。是的,“在父类构造期间,virtual函数不是virtual函数”^-^

理由:父类构造函数早于子类构造,此时子类的成员变量尚未初始化。若能下降到子类的virtual必然要取子类的成员变量。
有可能导致不明确行为。
在父类的构造期间,对象的类型是父类而非子类。不仅仅是virtual函数,日哟使用运行期类型信息(例dynamic_Cast和typeid),也会视为父类类型。

为了确保子类版本的logTransaction被调用,可以有以下方案:
在父类中将logTransaction改为non-virtual,并要求子类构造函数传递必要信息给Transaction构造函数。

class Transaction{
public:
    explicit Transaction(const std::string& logInfo);
    void logTransaction(const std::string& logInfo) const;
    ...
};
Transaction::Transaction(const std::string& logInfo)
{
    ...
    logTransaction(logInfo); // 志记交易
}
class BuyTransaction:public Transaction{
public:
    BuyTransaction(parameters):Transaction(createLogString(parameters))
    {...}
    ...
private:
    static std::string createLogString(paramerters); //令次函数为static避免了意外指向“初始未成熟之BuyTransaction对象内尚未初始化成员变量”。
};

原创粉丝点击