2013-11-27 9 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

Это только undefined, если вы удаляете экземпляр производного класса с помощью указателя на базовый класс. – interjay

+0

Верно, я приспособился для уточнения. –

Смежные вопросы