带继承和组合关系的类中构造函数和析构函数的调用顺序

1.构造函数

构造函数的调用顺序如下:

基类构造函数,C++提出的成员初始化列表,对象成员构造函数(非指针类型),派生类本身的构造函数。

2.析构函数调用顺序,

析构函数的调用顺序如下:(析构函数的调用顺序正好和构造函数的调用顺序相反)

派生类本身的析构函数,对象成员的析构函数,基类的析构函数。

这里没有写这个C++提出的成员初始化列表的原因是,他只是负责构造了,构造之后,析构就都是调用对象成员的析构函数了。

这里给出具体的例子看下:

首先这个例子先不给出 C++提出的成员初始化列表,让我们来引入问题,然后把它用C++提出的成员初始化列表 进行解决问题。

#include<iostream>
using namespace std;

class B{
public:
    B(){
        cout<<"B construct enter"<<endl;
    }
    ~B(){
        cout<<"B desconstruct enter"<<endl;
    }
    B(const B&other){
        cout<<"B copy construct enter"<<endl;
    }
    B& operator=(const B&other){
        cout<<"B assign operator enter"<<endl;
        B temp=other;
        return temp;
    }

};

class C{
public:
    C(){
        cout<< "C construct enter"<<endl;
    }
    ~C(){
        cout<<"C desconstruct enter"<<endl;
    }
};

class A:public C{
public:
    A(B&zhc){
        temp=zhc;
        cout<<"A construct enter"<<endl;
    }
    ~A(){
        cout<<"A desconstruct enter"<<endl;
    }
private:
    B temp;
};

int main(){
    B zyl;
    A zhc(zyl);
    return 0;
}

代码输出如下图所示 

上面的输出我们稍微总结下:

先调用父类的构造,然后调用成员变量的构造,然后调用自己的构造,但是因为在打印之前我们,先用构造函数传进来的参数给,自己的已经默认调用构造函数,完成构造的成员变量赋值了,temp=zhc;所以会调用一次赋值运算符重载。

然后析构顺序正好相反,这个我就不再详细的说了,但是我们发现,这个在效率上有点低,因为我们已经想要对自己的成员变量 B temp 通过这个构造函数进行赋初值,就不想让编译器进行调用默认的构造函数了,也就是你这次的调用没有任何的意义。

那么我们怎么解决这个问题呢,就是用成员列表的初始化,我为了详细而清晰的比较,成员列表初始化和这个成员变量的构造,哪个在前面执行,我又引入了一个,类D,作为A 的成员变量,让其自动调用构造函数初始化,然后我们再加入成员列表的初始化,初始化类A 的成员 B temp,就会解决这个问题,不会先调用 成员的默认构造,而是调用了成员函数的拷贝构造。

#include<iostream>
using namespace std;

class B{
public:
    B(){
        cout<<"B construct enter"<<endl;
    }
    ~B(){
        cout<<"B desconstruct enter"<<endl;
    }
    B(const B&other){
        cout<<"B copy construct enter"<<endl;
    }
    B& operator=(const B&other){
        cout<<"B assign operator enter"<<endl;
        B temp=other;
        return temp;
    }

};

class D{
public:
    D(){
        cout<< "D construct enter"<<endl;
    }
    ~D(){
        cout<<"D desconstruct enter"<<endl;
    }
};

class C{
public:

    C(){
        cout<< "C construct enter"<<endl;
    }
    ~C(){
        cout<<"C desconstruct enter"<<endl;
    }
};

class A:public C{
public:
    A(B&zhc):temp(zhc){
        cout<<"A construct enter"<<endl;
    }
    ~A(){
        cout<<"A desconstruct enter"<<endl;
    }

    void Display(){

    }
private:
    B temp;
    D temp1;
};

int main(){
    B zyl;
    A zhc(zyl);
    zhc.Display();
    return 0;
}

输入的结果如下:

B construct enter
C construct enter
B copy construct enter
D construct enter
A construct enter
A desconstruct enter
D desconstruct enter
B desconstruct enter
C desconstruct enter
B desconstruct enter

从结果中很容易证明我上面说的结论了。

构造函数的顺序 C(父类) B (成员列表)D (组合的对象)A(派生类自己)

析构函数顺序,A  D  B  C   与构造函数顺序相反。

3.强调一点,如果我们类中的组合成员是另外一个类对象的指针,就不会调用构造函数了。

也就是指针类型和其他基本类型是一致的,如int char 等。

4.就是关于有多个成员变量的情况,成员变量的初始化顺序与,声明顺序有关,声明顺序在前,则先进行初始化,注意一点,就是成员初始化列表的在前,是和一个成员变量自身比的,也就是如果是成员初始化列表的方式,和分成员初始化的方式,和它自己相比。   而不能说是成员初始化列表的成员变量,比 其它非成员列表初始化的都快,主要还是看声明顺序,如果是非成员列表初始化,那么会先进行一次默认的构造,然后还会进行一次赋值运算符重载,成员列表初始化只会进行一次拷贝构造。

#include<iostream>
   using namespace std;
   
 class B{
 public:
     B(){
         cout<<"B construct enter"<<endl;
     }
     ~B(){
          cout<<"B desconstruct enter"<<endl;
      }
      B(const B&other){
          cout<<"B copy construct enter"<<endl;
      }
      B& operator=(const B&other){
          cout<<"B assign operator enter"<<endl;
        //  B temp=other;
          return *this;
      }
  
  };
  
  class D{
  public:
      D(){
          cout<< "D construct enter"<<endl;
      }
      ~D(){
          cout<<"D desconstruct enter"<<endl;
      }
      D(const D&other){
           cout<<"D copy construct enter"<<endl;
       }
  
  };
   
  class C{
  public:
   
      C(){
        cout<< "C construct enter"<<endl;
      }
      ~C(){
          cout<<"C desconstruct enter"<<endl;
      }
  };
  
  class A:public C{
  public:
      A(B&zhc):temp(zhc){
          cout<<"A construct enter"<<endl;
      }
      ~A(){
          cout<<"A desconstruct enter"<<endl;
      }
  
      void Display(){
  
      }
  private:
      D temp1;
      B temp;
  };
  
  int main(){
      B zyl;
      A zhc(zyl);
      zhc.Display();
      return 0;
  }

输出结果如下:

B construct enter
C construct enter
D construct enter
B copy construct enter
A construct enter
A desconstruct enter
B desconstruct enter
D desconstruct enter
C desconstruct enter
B desconstruct enter

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值