(C++) 调用析构函数时的子类链销毁
(c++) subclass chain destruction when calling destructor
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 是一个抽象类,它主要链接类 (B,C,D)
所以就像我可能有这样的情况
B *x = new B {5};
B *x2 = new B {5}
D * y = new D{x,x2);
因此,当我执行delete y;
时,我想让它链式破坏其两个字段的 2 个指针,即(B 对象)。如何使 D 类的析构函数然后链式析构函数?
就像我展示的示例非常简单,但其他示例具有越来越多的层。我想确保删除所有内容,以免发生内存泄漏。
我的 D 类 dtor 应该看起来像这样吗?
~D(){
delete ptr1;
delete ptr2;
}
对于C类的情况,我会这样做吗?
~C(){
delete ptr;
}
因为我这样做了,但它不起作用,我得到了内存泄漏,所以有什么问题?
我认为你的问题是错误的,因为你说这是一个继承链,但在撰写B
时,C
和D
直接来自A
。
当你做new D
时,你有一个由A
、B
、C
和D
组成的复合对象——它们是按继承顺序构造的。
*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
对象知道的内容,只要我们使用x
就可以执行。如果我们使用 x
删除 ,我们将调用~A()
而不是~D()
。这就是为什么在这种情况下析构函数必须是虚拟的,这允许virtual ~A()
调用~D()
,最终将再次调用~A()
(真实的而不是虚拟发送)。
无论您是否使用多态/上转换,您的直觉都是正确的 - ~D()
应该只清理D
对象引入类(ptr1
和ptr2
)的内存,同样适用于~C()
(仅ptr
)。
泄漏可能是由于某处发生了对象切片。例如(如果你强制编译它),这比上面的例子更糟糕,因为对象数据不会被复制(与结构定义相对于所引用的对象类型是不完整的相反):
D d;
C * c = d; // not too bad, we can't refer to D-specific things.
C c2 = d; // bad, c2 is copied from D up to C superclass and no further.
请注意,仅将指针/引用传递给可能需要保存派生类型的对象,并确保使用虚拟析构函数。否则,您正在执行的操作是正确的,让每个类的析构函数只针对该类进行清理。
- 继承期间显示未知行为的子类
- 通过指向指针数组的指针访问子类的属性
- 从父类方法返回子类对象
- c++, 在子类中,如何在没有对象的情况下访问父类的方法?
- 将父类对象强制转换为子类的问题
- 避免在C++中重复子类定义
- 将QOpenGLWidget子类转换为使用Metal而不是OpenGL的子类是否可行?
- 如何初始化矢量的模板化子类
- C++ 继承:将子类传递给需要基类的函数并获取子类行为
- 有没有办法按值将纯抽象类的所有子类传递给 C++ 中的函数?
- 使用子类覆盖基类中定义的函数
- 子类地址等于虚拟基类地址?
- 将子类方法声明为基类的友元
- C++子类共享变量?
- 如何检查模板专用化是否是基本模板的子类?
- 仅让特定类'Fabric'构造类'Foo'及其所有子类的实例
- 使用模板参数重载C++方法:如何使其适用于模板的子类?
- 基类中的默认析构函数禁用子类中的移动构造函数(如果有成员)
- 如何在C++子类中访问父类的私有变量
- 将父类的子类的数据复制到具有相同父类的另一个类