結論:
實現多態時,我們通過基類指針指向子類對象,在delete基類指針時,我們希望先調用子類的析構函數,再調用父類的析構函數,要實現這個目的,析構函數就必須定義成虛函數,否則只會調用父類的析構函數,子類的析構函數不會被調用。
實驗1:析構函數不定義成虛函數
#include <iostream> using namespace std; class father { public: father(int num) { cout << "create father" << endl; // new申請的內存不用判空,new不到內存會拋出異常,不會返回空指針 father_ptr = new int(num); } ~father() { cout << "destory father" << endl; if (father_ptr != nullptr) { delete father_ptr; } // 釋放內存以后,一定記得置空,防止出現野指針 father_ptr = nullptr; } private: int *father_ptr; }; class child : public father { public: // 父類沒有無參構造函數,需要顯示調用父類構造函數 child(int x, int y) : father(x) { cout << "create child" << endl; child_ptr = new int(y); } ~child() { cout << "destory child" << endl; if (child_ptr != nullptr) { delete child_ptr; } child_ptr = nullptr; } private: int *child_ptr; }; int main() { father *ptr = new child(10, 20); delete(ptr); return 0; }
運行結果:結果說明不定義成虛函數,只會調用父類的析構函數,不會調用子類的析構函數,導致內存泄露。

實驗2:析構函數定義成虛函數
#include <iostream> using namespace std; class father { public: father(int num) { cout << "create father" << endl; // new申請的內存不用判空,new不到內存會拋出異常,不會返回空指針 father_ptr = new int(num); } virtual ~father() { cout << "destory father" << endl; if (father_ptr != nullptr) { delete father_ptr; } // 釋放內存以后,一定記得置空,防止出現野指針 father_ptr = nullptr; } private: int *father_ptr; }; class child : public father { public: // 父類沒有無參構造函數,需要顯示調用父類構造函數 child(int x, int y) : father(x) { cout << "create child" << endl; child_ptr = new int(y); } virtual ~child() { cout << "destory child" << endl; if (child_ptr != nullptr) { delete child_ptr; } child_ptr = nullptr; } private: int *child_ptr; }; int main() { father *ptr = new child(10, 20); delete(ptr); return 0; }
運行結果:父類和子類都正常析構了。

tips:良好的編程習慣,不管類中有沒有指針,有沒有動態申請內存,都應該把析構函數定義成虛函數,定義成虛函數總是不會錯的。
