為什么不要在構造函數中調用虛函數


  

先看一段在構造函數中直接調用虛函數的代碼:

#include <iostream>

class Base
{
public:
Base() { Foo(); } ///< 打印 1

virtual void Foo()
{
std::cout << 1 << std::endl;
}
};

class Derive : public Base
{
public:
Derive() : Base(), m_pData(new int(2)) {}
~Derive() { delete m_pData; }

virtual void Foo()
{
std::cout << *m_pData << std::endl;
}
private:
int* m_pData;
};

int main()
{
Base* p = new Derive();
delete p;
return 0;
}


 

這里的結果將打印:1。

  這表明第6行執行的的是Base::Foo()而不是Derive::Foo(),也就是說:虛函數在構造函數中“不起作用”。為什么?

  當實例化一個派生類對象時,首先進行基類部分的構造,然后再進行派生類部分的構造。即創建Derive對象時,會先調用Base的構造函數,再調用Derive的構造函數。

  當在構造基類部分時,派生類還沒被完全創建,從某種意義上講此時它只是個基類對象。即當Base::Base()執行時Derive對象還沒被完全創建,此時它被當成一個Base對象,而不是Derive對象,因此Foo綁定的是Base的Foo。

  C++之所以這樣設計是為了減少錯誤和Bug的出現。假設在構造函數中虛函數仍然“生效”,即Base::Base()中的Foo();所調用的是Derive::Foo()。當Base::Base()被調用時派生類中的數據m_pData還未被正確初始化,這時執行Derive::Foo()將導致程序對一個未初始化的地址解引用,得到的結果是不可預料的,甚至是程序崩潰(訪問非法內存)。

  總結來說:基類部分在派生類部分之前被構造,當基類構造函數執行時派生類中的數據成員還沒被初始化。如果基類構造函數中的虛函數調用被解析成調用派生類的虛函數,而派生類的虛函數中又訪問到未初始化的派生類數據,將導致程序出現一些未定義行為和bug。

 

轉自:http://www.cnblogs.com/carter2000/archive/2012/04/28/2474960.html


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com