今天遇到這樣一個問題:
class AParent 有一個成員 BParent* ptr 初始化爲 nullptr
class AChild 作爲 AParent 的子類,ptr = new BChild , 其中 BChild 是 BParent 的子類
爲了減少編譯時的依賴, AParent.h 上面聲明瞭 class BParent;
在 AParent.cpp 裏面雖然調用了 delete ptr, 但是並未在 AParent.cpp 裏面 include BParent.h
導致在 AParent.cpp 裏 delete ptr 時,會發現 既沒有走 BParent 的析構函數 ,也沒有走 BChild 的析構函數
站在編譯器的角度來看 , 由於 AParent.cpp 只有 BParent 的類聲明,並沒有類定義,所以 AParent.cpp 其實並不知道 delete ptr 時要走哪個析構函數。
這樣的代碼如果隱藏在比較複雜的系統裏,就可能會因爲少執行了許多析構函數,造成各種資源的泄漏。
解決的辦法也很簡單,只要在 AParent.cpp 頂上 incude BParent.h ,就可以讓 delete ptr 時呈正確的多態形式,執行到對應 BChild 和 BParent 的析構函數了。
我在想,如果編譯器在 delete ptr 時認爲在調用 BParent 的析構函數,從而直接報一個鏈接錯誤找不到 ~BParent() 的定義,就可以避免這樣的問題了。但是無論是 msvc 還是 xcode 的編譯器都沒有這樣做。可能是有更深層的原因。
通過這個問題,我要吸取2個教訓:
1.認識到 c++ 裏 delete 一個只有聲明、沒有定義的指針,無論是在編譯鏈接時,還是在運行時,都是不會有明確報錯的
2.需要注意的是在 .h 裏聲明瞭類,一定要記得在 cpp 裏面 include 對應的實現