建構函式和解構函式中的虛擬函式行為

建構函式和解構函式中的虛擬函式的行為在第一次遇到時通常會令人困惑。

#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);
}