(c ++)调用析构函数时的子类链破坏

时间:2016-07-07 22:09:19

标签: c++ subclass destructor superclass

class A { 
....
};

class B: public A {
int x;
...
};

class C: public A{
A * ptr;
.....
};

class D : public A {
A* ptr1;
A* ptr2;
....
};

注意:我使B,C,D的所有构造函数都没有包含在那里。 所以A(没有字段)是超类,我有3个子类(B,C和D),每个子类都有不同的字段。

A是一个抽象类,它主要是Class(B,C,D)的链接

所以我可能会遇到像

这样的情况
B *x = new B {5};
B *x2 = new B {5}
D * y = new D{x,x2);

所以,当我做delete y;时,我想让它链式破坏它的两个字段的两个指针(B对象)。我如何为D类构造析构函数然后链式破坏?

就像我展示的示例非常简单,但其他示例有越来越多的图层。我想确保删除所有内容,以免发生内存泄漏。

我的D级Dtor应该是这样的吗?

~D(){
delete ptr1;
delete ptr2;
}

对于C类的情况,我会这样做吗?

~C(){
    delete ptr;
    }

因为我这样做并且它不起作用我得到内存泄漏所以什么是错的?

1 个答案:

答案 0 :(得分:0)

我认为你的问题是错误的,因为你说它是一个继承链,但在撰写时BCD直接来自A。< / p>

当你new D发生了什么事情时,你有一个由ABCD组成的复合对象 - 它们是在继承中构建的顺序。

*y = {
    // B starts
    int x;
    // C starts
    A * ptr;
    // D starts
    A * ptr1;
    A * ptr2;
};

请注意,析构函数将以相反的顺序调用,D先调用C,依此类推,以相反的顺序清理内存(处理超类的依赖关系)。但是,这取决于您要删除的对象类型。

如果我们这样做:

D * y = new D;
A * x = y;
delete x;

我们已将y有效地视为A对象,这意味着我们仅限于A对象所知道的内容,并且只要我们使用{{1} }。如果我们使用x删除,我们将调用x而不是~A()。这就是为什么在这种情况下析构函数需要是虚拟的,这允许~D()调用virtual ~A(),这将最终再次调用~D()(真实的不是虚拟发货)。

无论您是否正在使用多态/上传,您的直觉都是正确的 - ~A()应该只清理~D()对象引入类的内存( Dptr1)同样适用于ptr2(仅~C())。

泄漏是因为对象切片发生在某处。例如(如果你强制这个编译),这比上面的例子更糟糕,因为不会复制对象数据(因为相对于被引用的对象的类型,结构定义是不完整的):

ptr

要非常小心,您只需将指针/引用传递给可能需要保存派生类型的对象,并确保使用虚拟析构函数。否则你正在做的是正确的,让每个类的析构函数只为该类清理。