2013-11-27 175 views
-3

問題基於以下類層次結構。C++虛擬析構函數

Base2* d3 = new Der3(); 
d3->v1(); 
delete d3; 

輸出是:

Base1 
Base1 
Der1 
Base2 
Der3 
v1 Base2 
~Base2 

我也得到一個exception.Why(只應該產生記憶leack)

class Base1 
{ 
public: 
    Base1() {std::cout << "Base1" << std::endl; } 
    ~Base1() {std::cout << "~Base1" << std::endl; } 
    virtual void v1() { std::cout << "v1 Base1" << std::endl; } 
    void v2() {std::cout << "v2 Base1" << std::endl;} 
    void v3() {std::cout << "v3 Base1" << std::endl;} 
}; 

class Base2 
{ 
public: 
    Base2() {std::cout << "Base2" << std::endl; } 
    ~Base2() {std::cout << "~Base2" << std::endl; } 
    void v1() { std::cout << "v1 Base2" << std::endl; } 
    void v2() {std::cout << "v2 Base2" << std::endl;} 
    void v3() {std::cout << "v3 Base2" << std::endl;} 
}; 

class Der1 : public Base1 
{ 
public: 
    Der1() {std::cout << "Der1" << std::endl; } 
    ~Der1() {std::cout << "~Der1" << std::endl; } 
    virtual void v1() { std::cout << "v1 Der1" << std::endl; } 
    virtual void v2() {std::cout << "v2 Der1" << std::endl;} 
    void v3() {std::cout << "v3 Der1" << std::endl;} 
}; 

class Der2 : public Base1,public Der1 
{ 
public: 
    Der2() {std::cout << "Der2" << std::endl; } 
    ~Der2() {std::cout << "~Der2" << std::endl; } 
    virtual void v1() { std::cout << "v1 Der2" << std::endl; } 
    void v2() {std::cout << "v2 Der2" << std::endl;} 
    void v3() {std::cout << "v3 Der2" << std::endl;} 
}; 

class Der3 : public Base1,public Der1,public Base2 
{ 
public: 
    Der3() {std::cout << "Der3" << std::endl; } 
    ~Der3() {std::cout << "~Der3" << std::endl; } 
    virtual void v1() { std::cout << "v1 Der3" << std::endl; } 
    void v2() {std::cout << "v2 Der3" << std::endl;} 
    void v3() {std::cout << "v3 Der3" << std::endl;} 
}; 
+6

析構函數不是虛擬的... – interjay

+0

你不確定的行爲,因爲你要刪除想到了一個指向類型不匹配最初分配的對象的類型和指針的類型不有一個虛擬析構函數(並且是實際分配類型的基類)。 –

+1

@interjay從標題判斷,我猜他知道這一點。他的問題是,他爲這種情況分配了某種定義的行爲,實際上它並未定義。 –

回答

5

你爲什麼說你應該只得到一個?內存泄漏?這是未定義的行爲;什麼都可能發生。

問題可能是因爲虛擬析構函數還用於確定釋放函數和傳遞給它的地址。在你的情況下,你最終將錯誤的地址傳遞給::operator delete。但這只是實踐中可能發生的事情。這是未定義的行爲,任何事情都可能發生。

1

如果您打算從類派生並使用指向基類的指針來刪除該對象,則必須聲明它的析構函數是虛擬的。否則,這是未定義的行爲。

class A 
{ 
public: 
    ~A() {} 
... 
}; 

class B : public A 
{ 
public: 
    ~B() {} 
... 
}; 

class C 
{ 
public: 
    virtual ~C() {} 
... 
}; 

class D : public C 
{ 
public: 
    virtual ~D() { } 
... 
}; 

B b; // OK, but bad practice 
A* pa = new B; // not ok - when you try to delete 
C* pc = new D; // ok 
+0

如果您通過指向基類的指針刪除派生類的實例,它只是未定義的。 – interjay

+0

誠然,我會調整澄清。 –