构造函数和析构函数中的虚拟函数行为

构造函数和析构函数中的虚函数的行为在第一次遇到时通常会令人困惑。

#include <iostream>
using namespace std;

class base { 
public:
    base() { f("base constructor"); }
    ~base() { f("base destructor"); }

    virtual const char* v() { return "base::v()"; }

    void f(const char* caller) { 
        cout << "When called from " << caller << ", "  << v() << " gets called.\n"; 
    }        
};

class derived : public base {
public:
    derived() { f("derived constructor"); }
    ~derived() { f("derived destructor"); }

    const char* v() override { return "derived::v()"; }

};

int main() {
     derived d;
}

输出:

从基础构造函数调用时,将调用 base :: v()
从派生构造函数调用时,将调用 derived :: v()
从派生析构函数调用时,将调用 derived :: v()
从 base 析构函数调用时,将调用 base :: v()

这背后的原因是派生类可以定义尚未初始化的其他成员(在构造函数的情况下)或已经销毁(在析构函数的情况下),并且调用其成员函数将是不安全的。因此,在构建和销毁 C++对象时,*this动态类型被认为是构造函数或析构函数的类,而不是更多派生类。

例:

#include <iostream>
#include <memory>

using namespace std;
class base {
public:
    base()
    {
        std::cout << "foo is " << foo() << std::endl;
    }
    virtual int foo() { return 42; }
};

class derived : public base {
    unique_ptr<int> ptr_;
public:
    derived(int i) : ptr_(new int(i*i)) { }
    // The following cannot be called before derived::derived due to how C++ behaves, 
    // if it was possible... Kaboom!
    int foo() override   { return *ptr_; } 
};

int main() {
    derived d(4);
}