C++对象模型5——对象的构造/析构

对象的构造/析构顺序

  1. 初始化虚基类,按照继承顺序,从左到右,从最深到最浅。
  2. 初始化按照继承顺序初始化父类,如果父类还有父类,则递归的初始化父类的父类。
  3. 初始化虚函数表和虚函数指针。
  4. 按照声明顺序初始化初始化列表中的成员,如果成员不在初始化列表中,则使用默认初始化构造初始化。
  5. 执行用户的初始化代码。

从初始化顺序中可以看出两点:1、如果用户在自己的初始化代码中使用了memcpy函数,可能破坏虚函数指针,导致程序运行出错。2、如果在父类的构造函数中调用虚函数,只能执行父类的虚函数,而无法调用子类的虚函数,因为这个时候的虚函数指针指向的是父类的虚函数数,子类的虚函数表还没有构造出来。

#include
using namespace std;

class A1{
public:
    A1(int val){
        cout << "A1()" << endl;
    }
    ~A1(){
        cout << "~A1()" << endl;
    }
};

class A2{
public:
    A2(int val){
        cout << "A2()" << endl;
    }
    
    ~A2(){
        cout << "~A2()" << endl;
    }
};

class B1 :public A1{
public:
    B1():A1(0){
        cout << "B1()" << endl;
    }

    ~B1(){
        cout << "~B1()" << endl;
    }
};

class B2 :virtual public A2{
public:
    B2():A2(0){
        cout << "B2()" << endl;
    }

    ~B2(){
        cout << "~B2()" << endl;
    }
};

class C :public B1, public B2{
public:
    C():A2(0){
        cout << "C()" << endl;
    }
    ~C(){
        cout << "~C()" << endl;
    }
};

int main(){
    C *c = new C();
    delete c;
    return 0;
}

这个代码主要想说明两件事,1、在虚继承中,虚基类的初始化应该由子类初始化,因为可能存在多个父类继承同一个虚基类的情况,虚基类的初始化会有歧义。2、按照顺序初始化初始化父类,但是会优先初始化虚基类。此外,还有一点值得注意,在多继承中,会有this指针调整的发生。

对象的虚构顺序恰恰和构造顺序相反,这也比较好理解,就像对栈的操作,入栈和出栈的顺序恰好相反。也就是说,析构的顺序为:

  1. 执行用户的代码。
  2. 以和声明顺序相反的顺序调用对象成员的析构函数(如果有的话)。
  3. 重新设置虚函数指针,使其指向子类的虚函数表。
  4. 和声明顺序相反的循序递归调用父类的析构的函数。
  5. 以相反的顺序调用虚基类的析构函数。

你可能感兴趣的:(C++对象模型5——对象的构造/析构)