1,從儲存空間角度
虛函式對應乙個虛表vtbl,可是這個vtbl其實是儲存在物件的記憶體空間的。問題出來了,如果建構函式是虛的,就需要通過 vtbl來呼叫,可是物件還沒有例項化,也就是記憶體空間還沒有,無法找到vtbl。所以建構函式不能是虛函式。
vtbl是在編譯期就建立了,各個虛函式這時被組織成了乙個虛函式的入口位址的陣列.而物件的隱藏成員--vptr是在執行期--也就是建構函式被呼叫時進行初始化的,這是實現多型的關鍵。
2,從使用角度
虛函式主要用於在資訊不全的情況下,能使過載的函式得到對應的呼叫。建構函式本身就是要初始化例項,那使用虛函式也沒有實際意義呀。所以建構函式沒有必要是虛函式。
虛函式的作用在於通過父類的指標或者引用來呼叫它的時候能夠變成呼叫子類的那個成員函式。而建構函式是在建立物件時自動呼叫的,不可能通過父類的指標或者引用去呼叫,因此也就規定建構函式不能是虛函式。
3、建構函式不需要是虛函式,也不允許是虛函式,因為建立乙個物件時我們總是要明確指定物件的型別,儘管我們可能通過實驗室的基類的指標或引用去訪問它。但析構卻不一定,我們往往通過基類的指標來銷毀物件。這時候如果析構函式不是虛函式,就不能正確識別物件型別從而不能正確呼叫析構函式。
4、從實現上看,vtbl在構造函式呼叫後才建立,因而建構函式不可能成為虛函式
從實際含義上看,在呼叫建構函式時還不能確定物件的真實型別(因為子類會調父類的建構函式);而且建構函式的作用是提供初始化,在物件生命期只執行一次,不是物件的動態行為,也沒有太大的必要成為虛函式
5、當乙個建構函式被呼叫時,它做的首要的事情之一是初始化它的vptr。因此,它只能知道它是「當前」類的,而完全忽視這個物件後面是否還有繼承者。 當編譯器為這個建構函式產生**時,它是為這個類的建構函式產生**- -既不是為基類,也不是為它的派生類(因為類不知道誰繼承它)。
所以它使用的vptr必須是對於這個類的vtbl。而且,只要它是最後的構造函式呼叫,那麼在這個物件的生命期內,vptr將 保持被初始化為指向這個vtbl, 但如果接著還有乙個更晚派生的建構函式被呼叫,這個建構函式又將設定vptr指向它的vtbl,等.直到最後的建構函式結束。vptr的狀態是由被最後呼叫的建構函式確定的。這就是為什麼構造函式呼叫是從基類到更加派生類順序的另乙個理由。
但是,當這一系列構造函式呼叫正發生時,每個建構函式都已經設定vptr指向它自己的vtbl。如果函式呼叫使用虛機制,它將只產生通過它自己的vtbl的呼叫,而不是最後的vtbl(所有建構函式被呼叫後才會有最後的vtbl)。
基類析構函式只能是虛函式:
派生類物件構造的時候先呼叫基類的建構函式再呼叫派生類的建構函式,析構的時候先呼叫派生類析構函式再呼叫基類析構函式。
其實這個很好理解,派生類的成員由兩部分組成,一部分是從基類那裡繼承而來,一部分是自己定義的。那麼在例項化物件的時候,首先利用基類建構函式去初始化從基類繼承而來的成員,再用派生類建構函式初始化自己定義的部分。
同時,不止建構函式派生類只負責自己的那部分,析構函式也是,所以派生類的析構函式會只析構自己的那部分,這時候如果基類的析構函式不是虛函式,則只能呼叫基類的析構函式析構從基類繼承來的那部分成員,而派生類自己的成員沒有被析構,所以就會出現只刪一半的現象,造成記憶體洩漏。
所以析構函式要定義成虛函式。
在用基類指標指向派生類時,
在基類析構函式宣告為virtual的時候,delete基類指標,會先呼叫派生類的析構函式,由於繼承關係再呼叫基類的析構函式。
在基類析構函式沒有宣告為virtual的時候,delete基類指標,只會呼叫基類的析構函式,而不會呼叫派生類的析構函式,這樣會造成銷毀物件的不完全。
個人舉例:base *p=new drived;
//new 過程,會先呼叫operator new分配空間,再呼叫dirived的constructor,在呼叫dirived的constructor時,會先呼叫bass的constructor再呼叫dirived的constructor,故delete p時,(在bass的destructor是virtual時)會先呼叫dirived的destructor再呼叫bass的destructor
基類虛析構函式
why虛析構函式?主要還是由於基類指標或引用可以不進行顯示型別轉換的情況下指向派生類物件。同時通過引用或者指標或引用呼叫方法時遵循 例如 定義了基類brass,派生類brassplus 如果viewacct 不是虛方法,則b1 ref.viewacct 和b2 ref.viewacct 均是使用br...
建構函式 析構函式 虛析構函式
說析構函式之前,先說下建構函式。建構函式用來完成對物件的一系列初始化操作,主要作用有 1.給建立的物件建立乙個識別符號 2.為物件資料成員開闢記憶體空間 3.完成物件資料成員的初始化 當並未顯示的定義建構函式時,會生成乙個預設的建構函式,預設建構函式不能完成物件資料成員的初始化,只能給物件建立一識別...
建構函式不能為虛函式,析構函式要為虛函式
1,從儲存空間角度 虛函式對應乙個vtable,這大家都知道,可是這個vtable其實是儲存在物件的記憶體空間的。問題出來了,如果建構函式是虛的,就需要通過 vtable來呼叫,可是物件還沒有例項化,也就是記憶體空間還沒有,無法找到vtable,所以建構函式不能是虛函式。2,從使用角度 虛函式主要用...