当前位置导航:炫浪网>>网络学院>>编程开发>>C++教程>>C++基础入门教程

C++箴言:绝不在构造或析构期调用虚函数

      你不应该在构造或析构期间调用虚函数,因为这样的调用不会如你想象那样工作,而且它们做的事情保证会让你很郁闷。如果你转为 Java 或 C# 程序员,也请你密切关注本文,因为在 C++ 急转弯的地方,那些语言也紧急转了一个弯。

      假设你有一套模拟股票处理的类层次结构,例如,购入流程,出售流程等。对这样的处理来说可以核查是非常重要的,所以随时会创建一个 Transaction 对象,将这个创建记录在核查日志中是一个适当的要求。下面是一个看起来似乎合理的解决问题的方法:

    class Transaction { // base class for all
      public: // transactions
       Transaction();

       virtual void logTransaction() const = 0; // make type-dependent
       // log entry
       ...
    };

    Transaction::Transaction() // implementation of
    {
      // base class ctor
      ...
      logTransaction(); // as final action, log this
    } // transaction

    class BuyTransaction: public Transaction {
      // derived class
      public:
       virtual void logTransaction() const; // how to log trans-
       // actions of this type
       ...
    };

    class SellTransaction: public Transaction {
    // derived class
    public:
      virtual void logTransaction() const; // how to log trans-
      // actions of this type
    ...
    };
      考虑执行这行代码时会发生什么:

    BuyTransaction b;
      很明显 BuyTransaction 的构造函数会被调用,但是首先,Transaction 的构造函数必须先被调用,派生类对象中的基类部分先于派生类部分被构造。Transaction 的构造函数的最后一行调用虚函数 logTransaction,但是结果会让你大吃一惊,被调用的 logTransaction 版本是在 Transaction 中的那个,而不是 BuyTransaction 中的——即使被创建的对象类型是 BuyTransaction。基类构造期间,虚函数从来不会向下匹配(go down)到派生类。取而代之的是,那个对象的行为就好像它的类型是基类。非正式地讲,基类构造期间,虚函数禁止。 这个表面上看起来匪夷所思的行为存在一个很好的理由。因为基类的构造函数在派生类构造函数之前执行,当基类构造函数运行时,派生类数据成员还没有被初始化。如果基类构造期间调用的虚函数向下匹配(go down)到派生类,派生类的函数理所当然会涉及到本地数据成员,但是那些数据成员还没有被初始化。这就会为未定义行为和悔之晚矣的调试噩梦开了一张通行证。调用涉及到一个对象还没有被初始化的部分自然是危险的,所以 C++ 告诉你此路不通。

 

共3页 首页 上一页 1 2 3 下一页 尾页 跳转到
相关内容
赞助商链接