簡體   English   中英

虛擬 function 的意外行為?

[英]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 destructorbase 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 ab以正確的順序調用析構函數。

[注意:如果您在某處放置了斷點並且您沒有單步執行,則只能觸發另一種方式。 :)]

我實際上已經厭倦了在 C++ 測試中看到,詢問在這種情況下會發生什么行為。 他們希望你回答它會調用 A 的析構函數而不是 B 的析構函數。

這不是保證的行為,您不能依賴它。 未定義的行為意味着您無法確定會發生什么,這里就是這種情況。

這也是“只是不要這樣做..”的一個例子。 在我的上一份工作中,我完全從系統中刪除了一個測試該行為的測試,理由是它無關緊要且偏離主題。

制作虛擬析構函數的另a選擇是使其受到保護。 這也將保護您main()將無法編譯,因為您無法從那里調用delete var 您甚至無法通過與main相同的方式在b中調用未定義的行為,因為您可能會感到驚訝,但deletea*在那里也將無法訪問。

boost::shared_ptr<a>( new b );

安全,因為它將為 b 而不是 a 創建一個刪除器。

由於a有另一個虛擬 function ,但您幾乎可以肯定 go 可以選擇使其析構函數為虛擬。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM