与这些非常相似的问题,除了不完全相同:What is the order in which the destructors and the constructors are called in C++ Order of member constructor and destructor calls
我想知道:派生类的成员变量是在调用基类的析构函数之前或之后销毁的吗?
这是使用Visual Studio 2008的C ++。谢谢。
答案 0 :(得分:13)
构造函数:第一个基础,然后派生
破坏:
代码:
class member {
string s;
public:
member(string s) {
this-> s = s;
}
~member() {
cout << "~member " << s << endl;
}
};
class base {
member m;
public:
base() : m("base"){
}
~base() {
cout << "~base" << endl;
}
};
class derived : base{
member m2;
public:
derived() :m2("derived") { }
~derived() {
cout << "~derived" << endl;
}
};
int main(int argc, const char * argv[]) {
derived s;
return 0;
}
当您计划动态分配(即当您使用关键字new
&amp; delete
)衍生对象时,始终会有virtual
或基础上的protected
析构函数。在下面的示例中,动态删除基类引用上的对象会导致内存泄漏:
class base {
member m;
public:
base() : m("base"){
}
/* correct behaviour is when you add **virtual** in front of the signature */
~base() {
cout << "~base" << endl;
}
};
class derived : public base{
member m2;
char* longArray;
public:
derived() :m2("derived") {
longArray = new char[1000];
}
~derived() {
delete[] longArray; // never called
cout << "~derived" << endl;
}
};
int main(int argc, const char * argv[]) {
base *s = new derived; // mind the downcast to **base**
delete s; /* only the non-virtual destructor on the base and its members is called.
No destructor on derived or its members is called.
What happens to the memory allocated by derived?
**longArray** is leaked forever.
Even without **longArray**, it most probably **leaks** memory, as C++ doesn't define its behaviour
*/
return 0;
}
输出:
仅清理基础数据,并longArray
泄露。
答案 1 :(得分:6)
这是标准所说的......(C ++ 11,12.4 / 8)
执行析构函数体并破坏体内分配的任何自动对象后,a 类
X
的析构函数调用X
的直接非变量非静态数据成员的析构函数,析构函数 对于X
的直接基类,如果X
是派生类最多的类(12.6.2),则它的析构函数调用X
的虚拟基类的析构函数。所有析构函数都被调用,就像它们被引用一个合格的 name,即忽略更多派生类中任何可能的虚拟覆盖析构函数。基地和 成员按其构造函数完成的相反顺序销毁(见12.6.2)。回报 析构函数中的语句(6.6.3)可能不会直接返回给调用者;在将控制转移到之前 调用者,成员和基地的析构者被称为。调用数组元素的析构函数 按其构造的相反顺序(见12.6)。
请注意,此顺序确实与C ++ 11中12.6.2 / 10中给出的顺序相反。您不能单独查看12.4 / 8的虚拟基础破坏顺序,但是您可以从12.6.2 / 10推断它,它指定虚拟基础的初始化发生在深度优先搜索左侧到正确的顺序。 (因此,虚拟碱基的破坏发生在该顺序的反面。)
无论如何,你有答案。首先销毁非静态成员,然后销毁基类。但是在下一个基类的析构函数启动之前,基类的成员将被销毁。它实际上就像深度优先搜索一样。