在多态中调用 3 层析构函数
Posted
技术标签:
【中文标题】在多态中调用 3 层析构函数【英文标题】:Calling 3 layers of destructors in polymorphism 【发布时间】:2016-04-05 00:17:55 【问题描述】:我真的被这个问题困住了。我有一个内存泄漏的应用程序。为了摆脱这个问题,我需要为类调用析构函数。
对于 2 层类,这个问题是微不足道的,但在这种情况下,有 3 层类,我找不到任何方法来编译:
#include<iostream>
using namespace std;
/* *MUST* be an abstract class and contains data that must be freed */
class C
public:
virtual ~C()=0;
;
/* Contains concrete methods and contains data that has to be freed */
class B:public C
public:
virtual ~B();
;
/* contains no data, only methods nothing needs to be freed in here */
class A:public B
public:
~A();
;
int main()
C *c = new A;
return 0;
当我编译代码时出现错误:
martyn@Hades ~ $ gcc deleteme.cpp -std=c++11
/tmp/cc7nxaw5.o: In function `main':
deleteme.cpp:(.text+0x12): undefined reference to `operator new(unsigned int)'
/tmp/cc7nxaw5.o: In function `__static_initialization_and_destruction_0(int, int)':
deleteme.cpp:(.text+0x4b): undefined reference to `std::ios_base::Init::Init()'
deleteme.cpp:(.text+0x62): undefined reference to `std::ios_base::Init::~Init()'
/tmp/cc7nxaw5.o: In function `B::B()':
deleteme.cpp:(.text._ZN1BC2Ev[_ZN1BC5Ev]+0x16): undefined reference to `vtable for B'
/tmp/cc7nxaw5.o: In function `A::A()':
deleteme.cpp:(.text._ZN1AC2Ev[_ZN1AC5Ev]+0x16): undefined reference to `vtable for A'
/tmp/cc7nxaw5.o:(.rodata._ZTV1C[_ZTV1C]+0x8): undefined reference to `__cxa_pure_virtual'
/tmp/cc7nxaw5.o:(.rodata._ZTV1C[_ZTV1C]+0xc): undefined reference to `__cxa_pure_virtual'
/tmp/cc7nxaw5.o:(.rodata._ZTI1C[_ZTI1C]+0x0): undefined reference to `vtable for __cxxabiv1::__class_type_info'
collect2: error: ld returned 1 exit status
谁能想出一种方法来重写析构函数,以便 A、B 和 C 的析构函数都被调用?
我正在用这个撕掉我的头发,任何帮助将不胜感激。但是,我无法更改 cmets 或继承层次结构中的要求,这样做需要我重写整个应用程序。
非常感谢。
编辑:非常感谢下面的问题,对我有用的解决方案是:
#include<iostream>
using namespace std;
/* *MUST* be an abstract class and contains data that must be freed */
class C
public:
virtual ~C()=0;
;
C::~C()
cout<<"destroying C"<<endl;
/* Contains concrete methods and contains data that have to be freed */
class B:public C
public:
~B();
;
B::~B()
cout<<"destroying B"<<endl;
/* contains no data, only methods nothing needs to be freed in here */
class A:public B
public:
~A();
;
A::~A()
cout<<"destroying A"<<endl;
int main()
C *c = new A;
delete c;
return 0;
非常感谢您的建议。
【问题讨论】:
给你的析构函数定义,也许它会更好。~B()
另外,添加delete c;
实际上会调用它们。或者更好:使用智能指针。
这让我很困惑:/* *MUST* be an abstract class and contains data that must be freed */
和 virtual ~C()=0;
。 C
有免费数据。只有C
应该对C
有足够的了解才能做到这一点。 C
应该有一个析构函数。澄清。您可以拥有一个纯虚拟析构函数,但仍然提供析构函数。很奇怪,但确实如此。
大家好,我想你已经部分解决了我的问题,如果我在抽象类中指定析构函数并使其成为纯虚拟,那么现在可以使用,我可以让 B 和 C 析构函数调用,尽管我仍然无法在 A 中调用析构函数。不确定是否要更改问题。实际上,如果我现在使用这些新信息可能会更好。
哦等等,这完全解决了我的问题。我需要一个带有定义的基类 C 纯虚拟类,然后是非虚拟类 B 和 A,然后调用所有析构函数。我认为 B 必须是一个不纯的虚拟析构函数或其他东西。非常感谢大家:)
【参考方案1】:
这里的解决方案是在需要它们的类中实现析构函数,让编译器处理其余部分。
首先,C 有一些数据需要释放,所以 C 得到一个像这样的析构函数:
class C
int* cp;
public:
C() cp = new int;
virtual ~C()
delete cp;
cout << "~C()" << endl;
virtual void someMethod()=0;
;
B 类应该实现纯虚函数,并且还有需要释放的数据,所以:
class B: public C
int* bp;
public:
B() bp = new int;
virtual ~B()
delete bp;
cout << "~B()" << endl;
virtual void someMethod()//some Implementation
;
最后,A 类只提供了一些方法,所以我们不需要析构函数。但我也会在此处包含一个用于演示:
class A: public B
public:
virtual ~A()
cout << "~A()" << endl;
;
构造这个类并使用delete
调用析构函数将正确调用所有三个析构函数:
int main()
C *c = new A;
delete c;
return 0;
输出:
~A()
~B()
~C()
Try it online
请注意:在您发布的代码中,您似乎尝试使用纯虚拟析构函数的声明来使您的类抽象。但是如果你必须释放类中的资源,你需要使用另一个函数来达到这个目的,如果你没有纯虚函数的话。
编辑: 阅读here 可以了解到,为同一函数提供纯说明符和定义确实是有效的——这也适用于析构函数。所以你确实可以这样做:
class C
virtual ~C() = 0;
;
C::~C() /*Implementation here*/
最后,只要至少一个函数是纯虚拟的 (=0
),你的类就是抽象的。如果这是析构函数或其他一些函数也没关系。但是如果你的类需要释放资源,你需要一个体作为你的析构函数。
【讨论】:
感谢您的回答,我留下的问题之一是您是否可以对析构函数的虚拟继承进行分层,看起来您可以。非常感谢 :) 我将不得不用实际的代码库测试这些解决方案,因为 C 是一个抽象类至关重要,因为有一个多态类实例的向量,如果 C 不是抽象的,我会打开一个潘多拉魔盒。 在这种情况下,C 是抽象的——不是析构函数使它抽象,而是someMethod()
效果很好——它还修复了我的内存泄漏。谢谢你。我现在有一个无内存泄漏的神经网络!以上是关于在多态中调用 3 层析构函数的主要内容,如果未能解决你的问题,请参考以下文章