使用继承在C ++中销毁的析构函数和成员变量的顺序是什么?

时间:2015-02-05 23:33:24

标签: c++ inheritance visual-studio-2008 destructor

与这些非常相似的问题,除了不完全相同: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 ++。谢谢。

2 个答案:

答案 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;
}

参考文献&amp;虚析构函数

当您计划动态分配(即当您使用关键字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推断它,它指定虚拟基础的初始化发生在深度优先搜索左侧到正确的顺序。 (因此,虚拟碱基的破坏发生在该顺序的反面。)

无论如何,你有答案。首先销毁非静态成员,然后销毁基类。但是在下一个基类的析构函数启动之前,基类的成员将被销毁。它实际上就像深度优先搜索一样。