1. 程式人生 > >C++中虛擬函式與函式

C++中虛擬函式與函式

解構函式為什麼要宣告為虛 函式???

基類的解構函式需要宣告為虛擬函式: 
當派生類物件經由一個基類指標被刪除,而該基類帶著一個non-virtual解構函式,實際執行時通常發生的是物件的派生類成員沒有被銷燬。這也就是區域性銷燬,會發生記憶體洩漏,所以我們通常將基類的解構函式需要宣告為虛擬函式。

class Base
{
public:
    Base()
       :_b(1)
   {
       cout << "Base()" << endl;
   }
   ~Base()
   {
       cout << "~Base()" << endl;
   }
protected:
   int _b;
};
class Derived : public Base
{
public:
   Derived()
       :_d(2)
   {
       cout << "Derived()" << endl;
   }
   ~Derived()
   {
       cout << "~Derivde()" << endl;
   }
protected:
   int _d;
};
void test()
{
   Base *p;
   p = new Derived;
   delete p;
}

執行結果:

可以發現程式只刪除了base class物件,造成了區域性銷燬。
解決:將基類的解構函式生命為virtual,此後刪除派生類物件就會銷燬整個物件,包括派生類成分。

class Base
{
public:
    Base()
       :_b(1)
   {
       cout << "Base()" << endl;
   }
   virtual ~Base()
   {
       cout << "~Base()" << endl;
   }
protected:
   int _b;
};
class Derived : public Base
{
public:
   Derived()
       :_d(2)
   {
       cout << "Derived()" << endl;
   }
   ~Derived()
   {
       cout << "~Derivde()" << endl;
   }
protected:
   int _d;
};
void test()
{
   Base *p;
   p = new Derived;
   delete p;
}

執行結果:

可以發現,如果將base class的解構函式宣告為虛擬函式,就不存在區域性銷燬的問題。

注意:

1.任何類只要帶有 virtual 函式都幾乎應該也有一個 virtual 解構函式。 

2.如果類不含 virtual 函式,通常表示他並不意圖被用做一個基類。當類不企圖被當作基類時候令其解構函式為virtual 往往是個餿主意,這個原因大家也可以想一下。

 

不能被宣告為虛擬函式的函式

1.普通函式

普通函式只能被過載,不能被重寫,宣告為虛擬函式沒有任何意義,因為編譯器會在編譯時繫結函式。

2.建構函式: 
因為建構函式本身就是為了明確初始化物件成員才產生的。如果建構函式是虛擬函式,就需要通過 vtable 來呼叫,但是此時物件還沒有例項化,無法找到 vtable ,所以不能為虛擬函式

。 
從實現上來看,vtable 是在建構函式呼叫之後才建立的,因而建構函式不能為虛擬函式,同時編譯器也根本無法通過編譯。

3.內聯成員函式: 
因為行內函數是為了在程式碼中直接展開,減少函式呼叫的花費,而虛擬函式是為了在繼承後物件能夠準確的執行自己的動作。 
而且行內函數在編譯時被展開,虛擬函式在執行時才能動態繫結

4.靜態成員函式: 
靜態成員函式對於每一個類來說只有一份,所有的物件公用一份程式碼,它的實現就不是為了構成多型,也沒有要動態繫結的必要性。

5.友元函式: 
因為友元函式並不支援繼承,對於沒有繼承特性的函式沒有虛擬函式的說法。