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

What order are destructors called and member variables destroyed in C++ using inhertitance?

与这些问题非常相似,只是不完全是:What is the order in which the destructors and the constructors are called in C++ Order of member constructor and destructor calls

我想知道:派生class的成员变量是在调用基class的析构函数之前还是之后销毁的?

这是在 C++ 中使用 Visual Studio 2008。谢谢。

构造函数:先基后导出

破坏:

  • ~派生
  • ~成员派生
  • ~基地
  • ~会员基础

代码:

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

引用和虚拟析构函数

当您计划动态分配(即当您使用关键字 newdelete)派生对象时,总是 有一个 virtual 或你基地上的 protected 析构函数。动态删除基于 class 引用的对象否则会导致 内存泄漏 ,如下例所示:

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 泄漏.

这是标准所说的...(C++11、12.4/8)

After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X’s direct non-variant non-static data members, the destructors for X’s direct base classes and, if X is the type of the most derived class (12.6.2), its destructor calls the destructors for X’s virtual base classes. All destructors are called as if they were referenced with a qualified name, that is, ignoring any possible virtual overriding destructors in more derived classes. Bases and members are destroyed in the reverse order of the completion of their constructor (see 12.6.2). A return statement (6.6.3) in a destructor might not directly return to the caller; before transferring control to the caller, the destructors for the members and bases are called. Destructors for elements of an array are called in reverse order of their construction (see 12.6).

注意这个顺序确实是C++11中12.6.2/10给出的顺序的倒序。单看12.4/8无法判断virtual bases的销毁顺序是什么,但是可以从12.6.2/10推断出来,12.6.2/10指定virtual bases的初始化发生在depth-first search left-to -正确的顺序。 (因此,虚拟基地的破坏以相反的顺序发生。)

无论如何,你有你的答案。非静态成员首先被销毁,然后是基础 classes。但是基础 class 的成员将在 next 基础 class 的析构函数启动之前被销毁。这真的和深度优先搜索一模一样。