Ked*_*arX 32 c++ inheritance destructor
析构函数(当然还有构造函数)与其他成员函数之间的区别在于,如果常规成员函数在派生类中具有主体,则只会执行Derived类中的版本.在析构函数的情况下,派生以及基类版本都会被执行吗?
很容易知道在析构函数(可能是虚拟的)和构造函数的情况下究竟发生了什么,即使删除了最多派生的类对象,也会为它们的所有基类调用它们.
提前致谢!
Pra*_*rav 16
标准说
在执行析构函数的主体并销毁在主体内分配的任何自动对象之后,类X的析构函数调用X的直接非变体成员的析构函数,X的直接基类的析构函数,如果X是最多的类型派生类(12.6.2),它的析构函数调用X的虚拟基类的析构函数.所有析构函数都被调用,就像它们被引用了一个限定名称一样,即忽略了更多派生类中任何可能的虚拟覆盖析构函数.基础和成员按照构造函数完成的相反顺序销毁(见12.6.2).析构函数中的return语句(6.6.3)可能不会直接返回给调用者; 在将控制转移给调用者之前,调用成员和基础的析构函数.数组元素的析构函数按其构造的相反顺序调用(见12.6).
此外,根据RAII,资源需要与合适对象的生命周期相关联,并且必须调用各个类的析构函数来释放资源.
例如,以下代码泄漏内存.
struct Base
{
int *p;
Base():p(new int){}
~Base(){ delete p; } //has to be virtual
};
struct Derived :Base
{
int *d;
Derived():Base(),d(new int){}
~Derived(){delete d;}
};
int main()
{
Base *base=new Derived();
//do something
delete base; //Oops!! ~Base() gets called(=>Memory Leak).
}
Run Code Online (Sandbox Code Playgroud)
ste*_*anB 13
构造函数和析构函数与常规方法的其他方法不同.
构造函数
struct A {};
struct B : A { B() : A() {} };
// but this works as well because compiler inserts call to A():
struct B : A { B() {} };
// however this does not compile:
struct A { A(int x) {} };
struct B : A { B() {} };
// you need:
struct B : A { B() : A(4) {} };
Run Code Online (Sandbox Code Playgroud)
析构函数:
struct C
{
virtual ~C() { cout << __FUNCTION__ << endl; }
};
struct D : C
{
virtual ~D() { cout << __FUNCTION__ << endl; }
};
struct E : D
{
virtual ~E() { cout << __FUNCTION__ << endl; }
};
int main()
{
C * o = new E();
delete o;
}
Run Code Online (Sandbox Code Playgroud)
输出:
~E
~D
~C
Run Code Online (Sandbox Code Playgroud)
如果基类中的方法被标记为virtual所有继承的方法都是虚拟的,那么即使你没有标记析构函数D,E因为virtual它们仍然是,virtual并且它们仍然以相同的顺序被调用.
Igo*_*aka 11
这是设计的.必须调用基类上的析构函数才能释放其资源.经验法则是派生类应该只清理自己的资源并让基类自行清理.
来自C++规范:
在执行析构函数的主体并销毁在主体内分配的任何自动对象之后,类X的析构函数调用X的直接成员的析构函数,X的直接基类的析构函数,如果X是派生类最多的类型( 12.6.2),它的析构函数调用X的虚拟基类的析构函数.调用所有析构函数,就好像它们是使用限定名称引用一样,即忽略更多派生类中的任何可能的虚拟覆盖析构函数.基础和成员按照构造函数完成的相反顺序销毁(见12.6.2).
此外,因为只有一个析构函数,所以类必须调用哪个析构函数没有歧义.构造函数不是这种情况,如果没有可访问的默认构造函数,程序员必须选择应该调用哪个基类构造函数.