要了解這個話題,首先我們給出一段**:
#include
using
namespace
std;
class animal
virtual
void eat()
void eat()
};int main()
執行結果如下:
包含虛函式的物件有以下的結構:
當基類中的資料成員是private型別的,繼承類的物件無法直接訪問資料成員,但是它又必須建立所有的資料物件。從上面的物件的結構,我們也發現,基類物件在上,繼承類的物件依次在下面。這也表明了如下的結論:
建構函式的呼叫次序是沿著類的生成過程進行的。因為只***了底層的正確,才能進一步構造。這樣的生成順序也是為了vptr的設定考慮的。因最終的vptr是most-derived的那個類的virtual table的位址,所以,從下往上的生成過程會用上層的vptr不斷覆蓋底層的,使得最終得到正確的vptr.如果在建構函式中呼叫虛函式會和在普通函式中有和區別呢?
眾所周知,建構函式是產生物件的函式,如果在建構函式中呼叫虛函式,那麼只能呼叫base類中的虛函式,並且在前面加上相應的namespace.如果什麼都不加,則預設是該物件中的虛函式。而普通成員函式中呼叫虛函式,則很有可能是乙個繼承當前類的乙個類中的成員函式。
下面用程式來進行說明:
#include
using
namespace
std;
class animal
virtual
void eat()
};class herbivore:public animal
void eat()
animal類中的成員函式description有乙個引用型別的引數,並且,該引數呼叫了乙個虛函式,因此需要在執行時決定其型別。
建構函式是不能被宣告為虛函式的。因為建構函式是piece-by-piece的模式來構建物件的。那麼析構函式可以麼?
下面來看乙個例子:
#include
using
namespace
std;
class base1
};class derived1:public base1
};class base2
};class derived2:public base2
執行結果如下:
從執行結果可得出下面的結論:reference如果將析構函式宣告為虛函式的話,可以保證按照從下往上的呼叫次序進行析構;否則,就只呼叫基類的析構函式。所以,將析構函式設定為虛函式則是必要的。
產生這種現象的原因是,當用基類的指標或引用來操作派生類的物件時,如果析構函式不設定為虛函式,那麼它對於基類來說是不可見的,因此無法正確的呼叫。
至於鏈式的析構,則是在析構函式內部實現的。和建構函式的思想類似。也是唯一使用這種鏈式機制的兩類函式。
thinking in c++
建構函式 析構函式 虛析構函式
說析構函式之前,先說下建構函式。建構函式用來完成對物件的一系列初始化操作,主要作用有 1.給建立的物件建立乙個識別符號 2.為物件資料成員開闢記憶體空間 3.完成物件資料成員的初始化 當並未顯示的定義建構函式時,會生成乙個預設的建構函式,預設建構函式不能完成物件資料成員的初始化,只能給物件建立一識別...
建構函式 析構函式 虛函式
在類中,建構函式用於初始化物件及相關操作。建構函式是不能宣告為虛函式的,因為虛函式對應乙個virtual table 虛函式表 這個表的位址是儲存在物件的記憶體空間的。而在執行建構函式前,物件尚未完成建立,記憶體都沒有被分配,所以無法去查詢虛函式表,它不存在,因此也就無法得知該呼叫哪乙個函式了。析構...
C 建構函式 析構函式 虛析構函式
一般地,建立物件和刪除物件時,父類建構函式 子類建構函式 子類析構函式 父類析構函式。特例 如果用new建立了乙個物件,並將父類的指標指向這個子類的物件,那麼用delete撤銷物件時,系統只執行基類的析構函式,而不執行派生類的析構函式。如果希望按照子類析構函式 父類析構函式的順序執行,那麼應該將基類...