[英]Unexpected behaviour of virtual function?
當我使用 Visual Studio 2010 運行 C++ 代碼時,如果派生的 class function 中的任何一個被聲明為虛擬,則程序會卡在刪除變量處。 有人可以解釋一下嗎?
void testInheritance()
{
class a
{
public :
char x;
void fn1()
{
std::cout<<"\n In Class A Function 1 : "<<x;
}
virtual void fn2()
{
std::cout<<"\n In Class A Function 2 : "<<x;
}
a()
{
x='A';
std::cout<<"\n In A() : "<<x;
}
~a()
{
std::cout<<"\n In ~A : "<<x;
}
};
class b: public a
{
public :
char y;
virtual void fn1()
{
std::cout<<"\n In Class B Function 1 : "<<y;
}
void fn3()
{
std::cout<<"\n In Class B Function 3 : "<<y;
}
b()
{
y='B';
std::cout<<"\n In B() : "<<y;
}
~b()
{
std::cout<<"\n In ~B : "<<y;
}
};
a* var = new b();
delete var;
}
更多信息:
我知道要調用 b::fn1 和 class b 的析構函數,我需要在基礎 class 即 class a 中聲明它們是虛擬的。 但是,如果我不這樣做,甚至不將 class b 中的任何 function (也沒有來自 class a)聲明為虛擬的,它應該完美地調用 fn1 和析構函數。 但是,當我將 b(但不是 a)的任何成員聲明為虛擬成員時,無論是新成員還是重載成員,它都會在使用 VS2010 編譯時掛起,而在 linux 上使用 gcc4.4.4 編譯時會中斷。 它應該調用任何一個析構函數並正常工作,但我無法理解程序中斷的原因。
此外,在 Visual Studio 2010 中使用 Intellitrace 時,我嘗試在代碼掛起處中斷代碼,我收到以下消息:
該進程似乎已死鎖(或未運行任何用戶模式代碼)。 所有線程都已停止。
您期待出現意外行為,因為您在程序中創建了未定義行為。
使用指向具有non-virtual destructor
的base
class 的指針刪除derived
的 class object 會導致Undefined Behavior
。 未定義的行為意味着任何事情都可能發生。
C++ 標准第 1.3.24 節規定:
允許的未定義行為的范圍從完全忽略具有不可預測結果的情況,到在翻譯或程序執行期間以環境特征的記錄方式表現(有或沒有發出診斷消息),到終止翻譯或執行(發出的診斷消息)。
如何解決問題?
Base class 中的析構函數應該是虛擬的。
您的析構函數不是虛擬的,您是否不允許delete
var
作為基本 class 指針。 很可能你只是得到了兩組行為,這取決於其他虛函數的存在。
你需要聲明析構函數virtual
如果“卡住”的意思是, b::~b()
沒有被調用,那么答案是, a::~a()
需要是virtual
。
您正在使用基本 class ( a
) 指針來保存class b
的 object 。 當你delete var;
,它只調用不是virtual
a::~a()
; 通過使其virtual
; a
和b
以正確的順序調用析構函數。
[注意:如果您在某處放置了斷點並且您沒有單步執行,則只能觸發另一種方式。 :)]
我實際上已經厭倦了在 C++ 測試中看到,詢問在這種情況下會發生什么行為。 他們希望你回答它會調用 A 的析構函數而不是 B 的析構函數。
這不是保證的行為,您不能依賴它。 未定義的行為意味着您無法確定會發生什么,這里就是這種情況。
這也是“只是不要這樣做..”的一個例子。 在我的上一份工作中,我完全從系統中刪除了一個測試該行為的測試,理由是它無關緊要且偏離主題。
制作虛擬析構函數的另a
選擇是使其受到保護。 這也將保護您main()
將無法編譯,因為您無法從那里調用delete var
。 您甚至無法通過與main
相同的方式在b
中調用未定義的行為,因為您可能會感到驚訝,但delete
到a*
在那里也將無法訪問。
boost::shared_ptr<a>( new b );
安全,因為它將為 b 而不是 a 創建一個刪除器。
由於a
有另一個虛擬 function ,但您幾乎可以肯定 go 可以選擇使其析構函數為虛擬。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.