c++ 構造/析構函式中呼叫虛函式的問題
參加某公司的面試,遇到乙個很有趣的問題,在構造/析構函式中呼叫虛函式,當時沒答出來,回來查了一下資料,整理如下:
測試**1:
#include "stdafx.h"
using namespace std;
class classa
{public:
classa(){
cout<<"classa::classa() begin"cout<<"------------"<
在vs2003執行結果如下
classa::classa() begin
classa::print()
classa::classa() end
classb::classb() begin
classb::print()
classb::classb() end
------------
classb::print()
------------
classb::~classb() begin
classb::print()
classb::~classb() end
classa::~classa() begin
classa::print()
classa::~classa() end
(對**稍作修改,在gcc中的編譯結果也是如此)
可以看到,在new classb時,雖然在父類classa的建構函式調了的是被classb覆蓋的虛函式print(),但是實際上還是呼叫的classa的print。這是因為
繼承類在構造的時候總是首先呼叫其基類的建構函式來對屬於其基類的部分進行構造,在這個時候,整個類被當作基類來處理,繼承類的部分對整個類來說好像不存在一樣,直到基類的建構函式退出並進入繼承類的建構函式,該類才被當作繼承類來出來處理。對析構也一樣,只是析構的順序正好相反。
進一步分析,如果在析構函式中呼叫純虛函式呢?將classa中的print()改為純虛函式
測試**2:
#include "stdafx.h"
using namespace std;
class classa
{public:
classa(){
cout<<"classa::classa() begin"cout<<"------------"<
編譯出錯:
test error lnk2019: 無法解析的外部符號 "public: virtual void __thiscall classa::print(void)" (?print@classa@@uaexxz) ,該符號在函式 "public: __thiscall classa::classa(void)" (??0classa@@qae@xz) 中被引用
gcc中也有類似提示
稍加改動,繼續測試:
測試**3:
#include "stdafx.h"
using namespace std;
class classa
{public:
classa(){
cout<<"classa::classa() begin"cout<<"------------"<
成功編譯,但是執行時出現runtime error的錯誤。編譯器不會繞彎啊。
最後,建議大家在建構函式中別做太複雜的事,最好只是對成員變數的初
始化工作。複雜點的操作另寫乙個初始化函式。
C 建構函式 析構函式 虛析構函式
一般地,建立物件和刪除物件時,父類建構函式 子類建構函式 子類析構函式 父類析構函式。特例 如果用new建立了乙個物件,並將父類的指標指向這個子類的物件,那麼用delete撤銷物件時,系統只執行基類的析構函式,而不執行派生類的析構函式。如果希望按照子類析構函式 父類析構函式的順序執行,那麼應該將基類...
C 中建構函式和析構函式避免呼叫虛函式的問題
一 建構函式避免呼叫虛函式的問題 在建構函式中呼叫虛成員函式,雖然這是個不很常用的技術,但研究一下可以加深對虛函式機制及物件構造過程的理解。這個問題也和一般直觀上的認識有所差異。先看看下面的兩個類定義。struct c180 virtual foo struct c190 public c180 v...
C 中建構函式和析構函式避免呼叫虛函式的問題
一 建構函式避免呼叫虛函式的問題 在建構函式中呼叫虛成員函式,雖然這是個不很常用的技術,但研究一下可以加深對虛函式機制及物件構造過程的理解。這個問題也和一般直觀上的認識有所差異。先看看下面的兩個類定義。include using namespace std struct c180 virtual v...