讀書筆記《Effective c++》 條款09 絕不在構造和析構函數中調用virtual函數


這點確實要注意,這個和delphi中是不一樣的,不過也可以理解成delphi的create函數並不等同於c++的構造函數。


using std::cout;
using std::endl;
using std::string;

class A
{
public:
	A()
	{
		test();
	}
protected:
	virtual void test() const
	{
		cout << "A.test()" << endl;
	}
};

class B : public A
{
public:
	B()
	{
		
	}
protected:
	virtual void test() const override
	{
		cout << "B.test()" << endl;
	}
};

int main()
{
	B b;   // 將會調用A.test()

	return 0;
}

上面代碼中在A的構造函數中調用了virtual函數test(),實際上執行的是父類的test而不是子類的test,雖然我們創建的是一個子類的對象,這是c++類構造的邏輯決定的:

在創建子類之前實際上先創建了一個父類,或者說在運行子類的構造函數之前,會先調用父類的構造函數,而在父類的構造函數運行期間,這個對象還是一個父類的對象,所以這時候這個對象根本不知道有子類,或者這麼說,就是這個對象的虛表指針實際上指向的是父類自己的虛表,所以導致調用的test實際上是父類自己的test,這個可以通過把虛表指針的地址打出來就能發現,而delphi的create函數沒有這個問題,即使是在父類的create調用虛函數,也能正常的展現多態特性。


析構函數同理。


總結:

在構造和析構期間不要調用virtual函數,因爲這類調用從不下降至derived class(比起當前執行構造函數和析構函數那層)




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章