將解構函式設定為虛擬函式,並且解構函式可以為純虛擬函式
為什麼基類的解構函式是虛擬函式?
在實現多型時,當用基類操作派生類,在析構時防止只析構基類而不析構派生類的狀況發生。
但如果不需要基類對派生類及物件進行操作,則不能定義虛擬函式,因為這樣會增加記憶體開銷.當類裡面有定義虛擬函式的時候,編譯器會給類新增一個虛擬函式表,裡面來存放虛擬函式指標,這樣就會增加類的儲存空間.所以,只有當一個類被用來作為基類的時候,才把解構函式寫成虛擬函式.
為什麼解構函式可以是純虛擬函式?
在某些類裡宣告純虛解構函式很方便。純虛擬函式將產生抽象類——不能例項化的類(即不能建立此型別的物件)。有些時候,你想使一個類成為抽象類,但剛好又沒有任何純虛擬函式。怎麼辦?因為抽象類是準備被用做基類的,基類必須要有一個虛解構函式,純虛擬函式會產生抽象類,所以方法很簡單:在想要成為抽象類的類裡宣告一個純虛解構函式。
class Test {
public:
virtual ~Test() = 0; // 宣告一個純虛解構函式
};
這個類有一個純虛擬函式,所以它是抽象的,而且它有一個虛解構函式,所以不會產生解構函式問題。但這裡還有一件事:必須提供純虛解構函式的定義:
Test::~Test() {} // 純虛解構函式的定義
這個定義是必需的,因為虛解構函式工作的方式是:最底層的派生類的解構函式最先被呼叫,然後各個基類的解構函式被呼叫。這就是說,即使是抽象類,編譯器也要產生對~awov的呼叫,所以要保證為它提供函式體。如果不這麼做,連結器就會檢測出來,最後還是得回去把它添上。
雖然抽象類的解構函式可以是純虛擬函式,但要例項化其派生類物件,仍必須提供抽象基類中解構函式的函式體。
抽象類的純虛擬函式的實現可以由自身給出,也可以由派生類給出。錯了,除了解構函式外,其他函式都不行,必須要在派生類中進行實現。
class a
{
public:
virtual ~a()=0;
};
class b:public a
{
public:
virtual ~b(){};
};
int main()
{
b bb;
return 1;
} 解構函式是純虛擬函式的亦為抽象類。
上面的例子所以錯誤,因為b繼承a後沒有改寫a的純虛擬函式,因此b也是抽象類,自然不能例項化。
修改如下則正確:
class a
{
public:
virtual ~a()=0;
};
class b:public a
{
public:
virtual ~b(){};
};
a::~a(){};//改寫a的純虛擬函式,此時a仍為抽象類
int main()
{
b bb;
return 1;
}
注意此時a仍為抽象類不能例項化,a aa則錯誤。