《 構造/析構/內聯/構造/靜態成員函數 》——在什麼情況下是否可以是虛函數?

1. 構造函數爲什麼不能爲虛函數?
a. 存儲空間角度: 虛函數的調用需要虛函數表指針,而該指針存放在對象的內容空間中,需要調用構造函數纔可以創建他的值,否則即使開闢了空間,則虛表指針爲隨機值,不會找到構造函數;若構造函數聲明爲虛函數,那麼由於對象還未創建,還沒有內存空間,更沒有虛函數表地址用來調用虛函數——構造函數了。

b. 使用上: 從實現上看,vbtl在構造函數調用後才建立,因而構造函數不可能成爲虛函數;

虛函數主要是實現多態,在運行時纔可以明確調用對象,根據傳入的對象類型,來調用函數當一個構造函數被調用時,它做的首要的事情之一是初始化它的V P T R。因此,它只能知道它是“當前”類的,而完全忽視這個對象後面是否還有繼承者。當編譯器爲這個構造函數產生代碼時,它是爲這個類的構造函數產生代碼- -既不是爲基類,也不是爲它的派生類(因爲類不知道誰繼承它)。

c. 所以它使用的V P T R必須是對於這個類的V TA B L E。而且,只要它是最後的構造函數調用,那麼在這個對象的生命期內, V P T R將保持被初始化爲指向這個V TA B L E, 但如果接着還有一個更晚派生的構造函數被調用,這個構造函數又將設置V P T R指向它的 V TA B L E,等.直到最後的構造函數結束。V P T R的狀態是由被最後調用的構造函數確定的。這就是爲什麼構造函數調用是從基類到更加派生 類順序的另一個理由。

2.析構函數可以使用虛函數?

對象已經創建,虛表指針存放析構函數的地址,基類與派生類都含有析構虛函數,創建基類與子類對象,都含有各類的虛表指針,當寫通用函數時,運行根據傳入對象的類型確定析構函數的地址,然後調用該析構函數。 但析構卻不一定,我們往往通過基類的指針來銷燬對象。這時候如果析構函數不是虛函數,就不能正確識別對象類型從而不能正確調用析構函數。

3.一個對象訪問普通成員函數和虛函數哪個更快?

訪問普通成員函數更快,因爲普通成員函數的地址在編譯階段就已確定,因此在訪問時直接調 用對應地址的函數,而虛函數在調用時,需要首先在虛函數表中尋找虛函數所在地址,因此相比普 通成員函數速度要慢一些

4. 在什麼情況下,析構函數需要是虛函數?

答:若存在類繼承關係並且析構函數中需要析構某些資源時,析構函數需要是虛函數,否則當使用父類指針指向子類對象,在delete時只會調用父類的析構函數,而不能調用子類的析構函數,造成內存泄露等問題

5.內聯函數、構造函數、靜態成員函數可以是虛函數嗎?

都不可以。內聯函數需要在編譯階段展開,而虛函數是運行時動態綁定的,編譯時無法展開; 構造函數在進行調用時還不存在父類和子類的概念,父類只會調用父類的構造函數,子類調用子類 的,因此不存在動態綁定的概念;靜態成員函數是以類爲單位的函數,與具體對象無關,虛函數是 與對象動態綁定的,因此是兩個不衝突的概念;

6.構造函數中可以調用虛函數嗎?

可以,但是沒有動態綁定的效果,父類構造函數中調用的仍然是父類版本的函數,子類中調用的仍然是子類版本的函數

7.請你回答一下爲什麼析構函數必須是虛函數?爲什麼C++默認的析構函數不是虛函數
參考回答:
將可能會被繼承的父類的析構函數設置爲虛函數,可以保證當我們new一個子類,然後使用基類指針指向該子類對象,釋放基類指針時可以釋放掉子類的空間,防止內存泄漏。

C++默認的析構函數不是虛函數是因爲虛函數需要額外的虛函數表和虛表指針,佔用額外的內存。而對於不會被繼承的類來說,其析構函數如果是虛函數,就會浪費內存。因此C++默認的析構函數不是虛函數,而是隻有當需要當作父類時,設置爲虛函數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章