作者:billy
版權聲明:著作權歸作者所有,商業轉載請聯繫作者獲得授權,非商業轉載請註明出處
前言
在C++的類中,當我們用到多態的時候會把基類中的某個函數定義爲虛函數,然後在子類中重新實現這個函數。在此過程中我們引發了一個討論,基類中的構造函數和析構函數是否也可以定義爲虛函數呢?下面我們一起來分析一下。
構造函數
首先我們來看一下構造函數的定義:
類的構造函數是類的一種特殊的成員函數,它會在每次創建類的新對象時執行。該類對象被創建時,編譯系統爲該對象分配內存空間,並自動調用該構造函數,由構造函數完成成員的初始化工作。
由定義我們知道構造函數主要是爲了在創建對象時完成初始化工作,初始化可以從一下幾個方向來考慮:
- 存儲空間
我們知道一旦在類中定義了虛函數就會有一個虛函數表 vtable,vtable 存儲於對象的內存空間中,通過虛指針 vptr來確認調用哪一個函數。
如果構造函數是虛的,那麼就需要通過 vtable來調用,但是此時對象還未實例化,即內存空間還沒有,是無法找到vtable的; - 實際使用
虛函數主要用於在信息不全的情況下,能使重載的函數得到對應的調用。構造函數本身就是要初始化實例,那使用虛函數就沒有實際意義; - 實際含義
在調用構造函數時還不能確定對象的真實類型(因爲子類會調父類的構造函數),而且構造函數的作用是提供初始化,在對象生命期只執行一次,不是對象的動態行爲,沒有必要成爲虛函數;
- 總結:構造函數不需要是虛函數,也不允許是虛函數,因爲創建一個對象時我們總是要明確指定對象的類型。
析構函數
析構函數的定義:
類的析構函數是類的一種特殊的成員函數,它會在每次刪除所創建的對象時執行。析構函數通常用於釋放在構造函數或在生命期內獲得的資源(如動態分配的內存)。從廣義上講,析構函數的作用並不僅僅限於釋放資源方面,它可以執行任意操作,用來執行對象即將被撤銷之前程序員所期待的任何操作。
在使用多態的時候,編譯器總是根據類型來調用類成員函數。但是一個派生類的指針可以安全地轉化爲一個基類的指針。這樣刪除一個基類的指針的時候,C++不管這個指針指向一個基類對象還是一個派生類的對象,調用的都是基類的析構函數而不是派生類的。如果你依賴於派生類的析構函數的代碼來釋放資源,而沒有重載析構函數,那麼會有資源泄漏。
- 總結: 析構函數可以爲虛函數,而且當使用基類指針或引用來調用子類時,最好將基類的析構函數聲明爲虛函數,否則可以存在內存泄露的問題。