從存儲空間角度看
虛函數相應一個指向vtable
虛函數表的指針,這大家都知道,但是這個指向vtable
的指針事實上是存儲在對象的內存空間的。
問題出來了,假設構造函數是虛的。就須要通過 vtable
來調用。但是對象還沒有實例化,也就是內存空間還沒有,怎么找vtable
呢?所以構造函數不能是虛函數。
從使用角度
虛函數主要用於在信息不全的情況下,能使重載的函數得到相應的調用。構造函數本身就是要初始化實例。那使用虛函數也沒有實際意義呀。
所以構造函數沒有必要是虛函數。
虛函數的作用在於通過父類的指針或者引用來調用它的時候可以變成調用子類的那個成員函數。
而構造函數是在創建對象時自己主動調用的,不可能通過父類的指針或者引用去調用(沒有存在的必要)。因此也就規定構造函數不能是虛函數。
構造函數不須要是虛函數。也不同意是虛函數
由於創建一個對象時我們總是要明白指定對象的類型。雖然我們可能通過基類的指針或引用去訪問它但析構卻不一定,我們往往通過基類的指針來銷毀對象。這時候假設析構函數不是虛函數,就不能正確識別對象類型從而不能正確調用析構函數。
從實現上看
vbtl
在構造函數調用后才建立,因而構造函數不可能成為虛函數。從實際含義上看,在調用構造函數時還不能確定對象的真實類型(由於子類會調父類的構造函數);並且構造函數的作用是提供初始化,在對象生命期僅僅運行一次,不是對象的動態行為,也沒有必要成為虛函數。
虛函數表實現角度
當一個構造函數被調用時。它做的首要的事情之中的一個是初始化它的VPTR
。
因此。它僅僅能知道它是“當前”類的,而全然忽視這個對象后面是否還有繼承者。當編譯器為這個構造函數產生代碼時,它是為這個類的構造函數產生代碼——既不是為基類,也不是為它的派生類(由於類不知道誰繼承它)。
所以它使用的VPTR
必須是對於這個類的VTABLE
。並且,僅僅要它是最后的構造函數調用,那么在這個對象的生命期內。VPTR
將保持被初始化為指向這個VTABLE
, 但假設接着另一個更晚派生的構造函數被調用,這個構造函數又將設置VPTR
指向它的VTABLE
,等直到最后的構造函數結束。VPTR
的狀態是由被最后調用的構造函數確定的。這就是為什么構造函數調用是從基類到更加派生類順序的另一個理由。但是,當這一系列構造函數調用正發生時。每一個構造函數都已經設置VPTR
指向它自己的VTABLE
。假設函數調用使用虛機制。它將僅僅產生通過它自己的VTABLE
的調用,而不是最后的VTABLE
(全部構造函數被調用后才會有最后的VTABLE
)。