[轉] C++ 父類構造/析構函數中調用虛函數

轉自[https://blog.csdn.net/K346K346/article/details/49872023]ios

雖然能夠對虛函數進行實調用,但程序員編寫虛函數的本意應該是實現動態聯編。在構造函數中調用虛函數,函數的入口地址是在編譯時靜態肯定的,並未實現虛調用。可是爲何在構造函數中調用虛函數,實際上沒有發生動態聯編呢?程序員

第一個緣由,在概念上,構造函數的工做是爲對象進行初始化。在構造函數完成以前,被構造的對象被認爲「未徹底生成」。當建立某個派生類的對象時,若是在它的基類的構造函數中調用虛函數,那麼此時派生類的構造函數並未執行,所調用的函數可能操做尚未被初始化的成員,將致使災難的發生。函數

第二個緣由,即便想在構造函數中實現動態聯編,在實現上也會遇到困難。這涉及到對象虛指針(vptr)的創建問題。在Visual C++中,包含虛函數的類對象的虛指針被安排在對象的起始地址處,而且虛函數表(vtable)的地址是由構造函數寫入虛指針的。因此,一個類的構造函數在執行時,並不能保證該函數所能訪問到的虛指針就是當前被構造對象最後所擁有的虛指針,由於後面派生類的構造函數會對當前被構造對象的虛指針進行重寫,所以沒法完成動態聯編。spa

一樣的,在析構函數中調用虛函數,函數的入口地址也是在編譯時靜態決定的。也就是說,實現的是實調用而非虛調用。
考察以下例子。.net

#include <iostream>
using namespace std;

class A 
{
public:
	virtual void show(){
		cout<<"in A"<<endl;
	}
	virtual ~A(){show();}
};

class B:public A 
{
public:
	void show(){
		cout<<"in B"<<endl;
	}
};

int main()
{
	A a;
	B b;
}

  輸出爲:指針

in A
in A

  

在類B的對象b退出做用域時,會先調用類B的析構函數,而後調用類A的析構函數,在析構函數~A()中,調用了虛函數show()。從輸出結果來看,類A的析構函數對show()調用並無發生虛調用。對象

從概念上說,析構函數是用來銷燬一個對象的,在銷燬一個對象時,先調用該對象所屬類的析構函數,而後再調用其基類的析構函數,因此,在調用基類的析構函數時,派生類對象的「善後」工做已經完成了,這個時候再調用在派生類中定義的函數版本已經沒有意義了。blog

所以,通常狀況下,應該避免在構造函數和析構函數中調用虛函數,若是必定要這樣作,程序猿必須清楚,對虛函數的調用實際上是實調用。

作用域

相關文章
相關標籤/搜索