C++虚拟析构函数

C++ virtual destructor

本文关键字:析构函数 虚拟 C++      更新时间:2023-10-16

问题基于以下类层次结构。

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

输出为:

Base1
Base1
Der1
Base2
Der3
v1 Base2
~Base2

我有个例外。为什么?(只应生成内存泄漏)

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;}
};

为什么说只应该得到内存泄漏?这是未定义的行为;任何事情都有可能发生。

问题可能是因为虚拟析构函数还用于确定释放函数和传递给它的地址。在您的情况下,您最终会将错误的地址传递给::operator delete。但这正是实践中可能发生的事情。这是未定义的行为,任何事情都可能发生。

如果计划从类派生并使用指向基类的指针来删除对象,则必须声明它是析构函数虚拟的。否则,它就是未定义的行为。

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