C++学习——构造函数,析构函数与虚函数关系
文章目錄
- 1.構造函數,析構函數可以為虛函數嗎?
- 2.析構函數和構造函數的作用?
- 3.構造函數和析構函數調用順序?
- 4.類什么時候會調用析構函數?
1.構造函數,析構函數可以為虛函數嗎?
構造函數不可以,析構函數可以
從存儲空間角度,虛函數相應一個指向vtable虛函數表的指針,這大家都知道,但是這個指向vtable的指針事實上是存儲在對象的內存空間的。問題出來了,假設構造函數是虛的,就須要通過 vtable來調用,但是對象還沒有實例化,也就是內存空間還沒有,怎么找vtable呢?所以構造函數不能是虛函數。
從使用角度,虛函數主要用于在信息不全的情況下,能使重載的函數得到相應的調用。構造函數本身就是要初始化實例,那使用虛函數也沒有實際意義呀。所以構造函數沒有必要是虛函數。虛函數的作用在于通過父類的指針或者引用來調用它的時候可以變成調用子類的那個成員函數。而構造函數是在創建對象時自己主動調用的,不可能通過父類的指針或者引用去調用,因此也就規定構造函數不能是虛函數。
構造函數不須要是虛函數,也不同意是虛函數,由于創建一個對象時我們總是要明白指定對象的類型,雖然我們可能通過實驗室的基類的指針或引用去訪問它但析構卻不一定,我們往往通過基類的指針來銷毀對象。這時候假設析構函數不是虛函數,就不能正確識別對象類型從而不能正確調用析構函數。
從實現上看,vbtl在構造函數調用后才建立,因而構造函數不可能成為虛函數從實際含義上看,在調用構造函數時還不能確定對象的真實類型(由于子類會調父類的構造函數);并且構造函數的作用是提供初始化,在對象生命期僅僅運行一次,不是對象的動態行為,也沒有必要成為虛函數。
當一個構造函數被調用時,它做的首要的事情之中的一個是初始化它的VPTR。因此,它僅僅能知道它是“當前”類的,而全然忽視這個對象后面是否還有繼承者。當編譯器為這個構造函數產生代碼時,它是為這個類的構造函數產生代碼——既不是為基類,也不是為它的派生類(由于類不知道誰繼承它)。所以它使用的VPTR必須是對于這個類的VTABLE。并且,僅僅要它是最后的構造函數調用,那么在這個對象的生命期內,VPTR將保持被初始化為指向這個VTABLE, 但假設接著另一個更晚派生的構造函數被調用,這個構造函數又將設置VPTR指向它的 VTABLE,等.直到最后的構造函數結束。VPTR的狀態是由被最后調用的構造函數確定的。這就是為什么構造函數調用是從基類到更加派生類順序的還有一個理由。可是,當這一系列構造函數調用正發生時,每一個構造函數都已經設置VPTR指向它自己的VTABLE。假設函數調用使用虛機制,它將僅僅產生通過它自己的VTABLE的調用,而不是最后的VTABLE(全部構造函數被調用后才會有最后的VTABLE)。
因為構造函數本來就是為了明確初始化對象成員才產生的,然而virtual function主要是為了再不完全了解細節的情況下也能正確處理對象。另外,virtual函數是在不同類型的對象產生不同的動作,現在對象還沒有產生,如何使用virtual函數來完成你想完成的動作。
C++中基類采用虛析構函數是為了防止內存泄漏。
具體地說,如果派生類中申請了內存空間,并在其析構函數中對這些內存空間進行釋放。
假設基類中采用的是非虛析構函數,當刪除基類指針指向的派生類對象時就不會觸發動態綁定,因而只會調用基類的析構函數,而不會調用派生類的析構函數。
那么在這種情況下,派生類中申請的空間就得不到釋放從而產生內存泄漏。所以,為了防止這種情況的發生,C++中基類的析構函數應采用virtual虛析構函數。
基類構造函數沒有定義為虛函數,所以delete ptr只調用了基類的析構函數,沒有調用派生類的構造函數,造成內存泄露。
#include<iostream> using namespace std;class base { public:base() {}virtual void print() {cout << "base function" << endl;}virtual ~base() {cout << "base析構函數" << endl;} };class derived :public base{ public:derived(){}virtual void print() {cout << "derived function" << endl;}~derived(){cout << "derived析構函數" << endl;} }; int main() {base* ptr = new derived;ptr->print();delete ptr;return 0; } derived function derived析構函數 base析構函數2.析構函數和構造函數的作用?
構造函數只是起初始化值的作用
析構函數與構造函數的作用相反,用于撤銷對象的一些特殊任務處理,可以是釋放對象分配的內存空間;
析構函數的特點:析構函數與構造函數同名,但該函數前面加~。 析構函數沒有參數,也沒有返回值,而且不能重載,在一個類中只能有一個析構函數。 當撤銷對象時,編譯器也會自動調用析構函數。 每一個類必須有一個析構函數,用戶可以自定義析構函數,也可以是編譯器自動生成默認的析構函數。一般析構函數定義為類的公有成員。
3.構造函數和析構函數調用順序?
構造函數順序
① 基類構造函數。如果有多個基類,則構造函數的調用順序是某類在類派生表中出現的順序,而不是它們在成員初始化表中的順序。
② 成員類對象構造函數。如果有多個成員類對象則構造函數的調用順序是對象在類中被聲明的順序,而不是它們出現在成員初始化表中的順序。
③ 派生類構造函數。
析構函數順序
① 調用派生類的析構函數;
② 調用成員類對象的析構函數;
③ 調用基類的析構函數。
4.類什么時候會調用析構函數?
對象生命周期結束,被銷毀時;
delete指向對象的指針時,或delete指向對象的基類類型指針,而其基類虛構函數是虛函數時;
對象i是對象o的成員,o的析構函數被調用時,對象i的析構函數也被調用。
總結
以上是生活随笔為你收集整理的C++学习——构造函数,析构函数与虚函数关系的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue学习笔记-01-前端的发展历史(从
- 下一篇: GIS单词汇总