為什麼建構函式和析構函式中不應該呼叫虛函式

2021-08-10 06:54:17 字數 1195 閱讀 3192

在語法上,構造函式呼叫虛函式當然是沒有問題的。但是這種用法不一定能得到想要的結果,還會引發一些小問題。

class base ;

virtual

void func1() ;

virtual

void func2() ;

};class derived:public base ;

virtual

void func1() ;

virtual

void func2() ;

};

以上有兩個類

通過如下方式呼叫

void main()

列印結果為:

base::func1

base::func2

derived::func1

derived::func2

當我們例項化乙個派生類的時候,基類構造函式呼叫的virtual function定義是base::func1和base::func2,而derived建構函式是正常的,這是因為虛函式通過虛指標來訪問,乙個物件維護乙個虛指標,在物件建構函式開始執行之時,在對像執行初始化之前,虛指標生成,基類的這個虛指標只能訪問基類定義的虛函式。

為什麼c++要這麼做呢,直接支援多型不好嗎?因為派生類構造完成之前,基類構造之時,子類並沒有形成,子類資料成員當然就沒有初始化,也許是為了防止出現訪問未定義bug,c++只允許基數呼叫自己定義的虛函式。

所以建構函式中的多型特徵失效了。

上面的問題如果對於cpp有一定的了解是可以完美的規避的,不會出現任何意料之外的情況。

但是乙個c++高手卻不一定能隨時注意到乙個冗餘的函式呼叫的問題。

上面的類定義中,基類的兩個虛函式被子類重寫,當我只想例項化乙個子類物件的時候,如果基類像上面的一樣呼叫了兩個被過載的函式,這顯然不是乙個好的決定,比如重複對成員進行賦值、拷貝、計算等等。所以我們不應該在建構函式中呼叫虛函式。

同樣的,我們也不應該在析構函式中呼叫虛函式,基本上是和上面提到的同樣的原因。析構是由內向外析構的過程,子類在前,父類在後,如果子類析構函式先通過乙個虛函式把乙個成員物件釋放了,父類的析構函式再通過乙個虛函式把這個成員釋放一次,顯然就出問題了。

當然這些問題都是對語法沒吃透的原因,但是如果我們能夠按照一定的規範去實現**,規避這些問題,當然是最好的,因為誰也不能保證用危險的**會不犯錯。

為什麼在析構函式中不應該丟擲異常

1.丟擲異常 1.1 丟擲異常 也稱為拋棄異常 即檢測是否產生異常,在c 中,其採用throw語句來實現,如果檢測到產生異常,則丟擲異常。該語句的格式為 throw 表示式 如果在try語句塊的程式段中 包括在其中呼叫的函式 發現了異常,且拋棄了該異常,則這個異常就可以被try語句塊後的某個catc...

建構函式和析構函式

建構函式沒有返回值,不能被顯示的呼叫。它是在定義物件時由系統自動執行的,而且只執行一次。如果沒有定義建構函式,系統會自動生成乙個建構函式,只是這個建構函式的函式體是空,沒有引數,也不執行任何初始化的操作。帶引數的建構函式 有一種簡練,方便的寫法 建構函式的引數初始化表 box int h,int w...

析構函式和建構函式

每個物件生成的時候都要完成物件的初始化,如設定屬性的初始值。c 中規定每個類都有乙個初始值,如果沒有,系統會產生乙個預設的建構函式。這個建構函式沒有任何引數,不做任何額外的工作。但往往我們會自己寫乙個建構函式,用來進行特殊的初始化工作。這樣的話,編譯器就不會再為其生成預設的建構函式。class 類名...