C++建構函式和解構函式--從常見的面試題說起系列1
class A
{
public:
A(){a=0}
virtual ~A(){printf "aaa";}}
private:
int a;
}
class B: public A
{
public:
B(){a=2}
virtual ~B(){printf "bbb";}
}
常常有這樣兩個面試題目:
1)
A* p = new B;
delete p;
p->a 等於多少?
2)
解構函式的列印順序.
類A 和 類B的解構函式為什麼要定義為虛擬函式,如果不定義為虛擬函式會有什麼問題或隱患?
其實這兩道題目就是考的C++中類的建構函式和解構函式的呼叫順序問題,其中第一套題比較簡單,大部分面試者都能正確回答,第二道題回答完整的就比較少了,第二題還考到了多型(虛擬函式)的知識點,多型在後續的文章單獨闡述。
建構函式:
對於有整合關係的建構函式,定義子類的物件時,會先呼叫父類的建構函式,再呼叫子類的解構函式。
因此第一套題先回呼叫A的建構函式,此時b.a為0,然後呼叫B的建構函式,最終b.a的值為2.
解構函式:
對於解構函式,大部分面試者回答的比較簡單,回答的不夠全面。
刪除物件時,呼叫的第一個解構函式,由解構函式是否是虛擬函式確定:
1)如果是虛擬函式,則會呼叫指標指向的實際物件的類的解構函式,但是解構函式不僅僅是虛擬函式,它還會自動往上呼叫基類的解構函式。
2)如果不是虛擬函式,則由刪除指標定義的型別來確定。
這道題中,delete p時,由於是解構函式,則會先呼叫B的解構函式,再呼叫A的解構函式
如果不是虛擬函式,則只會呼叫A的解構函式。但是如果是 B* p = new B的話,即使不是虛擬函式,也一樣會先呼叫B的解構函式,再呼叫A的解構函式。
類成員申請的資源通常都是在解構函式中釋放,由於解構函式的這個特點,因此解構函式通常定義為虛擬函式,因為如果不是虛擬函式的話,很有可能不會呼叫到子類的解構函式,導致子類申請的資源沒有被釋放。