構造函數不能夠是虛函數的,這個很顯然,畢竟虛函數都對應一個虛函數表,虛函數表是存在對象內存空間的,若是構造函數是虛的,就須要一個虛函數表來調用,可是類還沒實例化沒有內存空間就沒有虛函數表,這根本就是個死循環。函數
但是析構函數卻要定義成虛函數,這是爲何呢,寫一個很是簡單的例子來理解一下:spa
class AA { public: AA() {}; ~AA() { fun2(); }; virtual void fun1() { cout << "Base construct" << endl; } virtual void fun2() { cout << "Base destruct" << endl; } }; class BB : public AA { public: BB() { fun1(); }; ~BB() { fun2(); }; void fun1() { cout << "Derive construct" << endl; } void fun2() { cout << "Derive destruct" << endl; } }; int main() { for (int i = 0; i < 1; i++) { //AA a; BB b; } return 0; }
輸出結果:code
因此能夠看出,派生類對象構造的時候先調用基類的構造函數再調用派生類的構造函數,析構的時候先調用派生類析構函數再調用基類析構函數。對象
其實這個很好理解,派生類的成員由兩部分組成,一部分是從基類那裏繼承而來,一部分是本身定義的。那麼在實例化對象的時候,首先利用基類構造函數去初始化從基類繼承而來的成員,再用派生類構造函數初始化本身定義的部分。blog
同時,不止構造函數派生類只負責本身的那部分,析構函數也是,因此派生類的析構函數會只析構本身的那部分,這時候若是基類的析構函數不是虛函數,則不能調用基類的析構函數析構從基類繼承來的那部分紅員,因此就會出現只刪一半的現象,形成內存泄漏。繼承
因此析構函數要定義成虛函數。內存