C++继承中构造顺序

原文地址:https://www.cnblogs.com/lawlietfans/p/5861769.html

规范的派生类构造函数有3个要点:

1.首先创建基类对象。

2.应通过成员初始化列表,创建基类对象。

3.应初始化本派生类新增成员变量。

第一种:不显示调用基类构造函数

C继承B1和B2

#include "iostream"
using namespace std
class B1
{
  public:
    B1(){cout<<"B1"<<endl;}  
};
class B2
{
  public:
    B2(){cout<<"B2"<<endl;}
}
class C:public B1,publc B2
{
    public:
    C(){cout<<"C"<<endl;}
}
int main()
{
    C obj;
    return 0;
}
/*output:
B1
B2
C
*/

其中,冒号指出C的基类是B1和B2,public限定符指出B1和B2都是公有基类,我们称之为公有派生。

公有派生中,基类的公有成员(成员变量、成员方法)变成了派生类的公有成员。基类的私有成员变成了派生类的私有成员,但是不能直接访问,只能借助基类的public和protected方法访问。

这时,程序将使用基类默认构造函数。
也就是说C的写法相当于在成员初始化列表调用基类的默认构造函数:

C():B1(),B2(){cout<<"C"<<endl;}
  • B1和B2的构造顺序只和继承的顺序有关,和成员初始化列表中的顺序无关.
  • 调整继承顺序  class C:public B2,public B1。输出顺序为B2,B1。而修改成员初始化列表中的顺序没有效果。

第二种:显示调用基类构造函数

同样的,B1和B2的构造顺序只和继承的顺序有关,和成员初始化列表中的顺序无关

class B1
{
    B1(){cout<<"B1"<<endl;}
    B1(int i){cout<<"B1:"<<i<<endl;}
};
class B2
{
    B2(){cout<<"B2"<<endl;}
    B2(int i){cout<<"B2:"<<i<<endl;}
}
class C:public B2,public B1
{
    C():B1(10),B2(20){cout<<"C"<<endl;};
}
int main()
{
    C obj;
    return 0;
}
/*output:
    B2:20
    B1:10
    C
*/

更进一步可以把C中构造函数参数作为实参传递给基类构造函数:

C(int x, int y):B2(x),B1(y){cout<<"C"<<endl;}

第三种:封闭类

有成员对象的类称为封闭类,这是对象组合的一种实现方式。

class C:public B2,public B1
{
    private:
    int x;
    B1 memberb1;
    B2 memberb2;
    public:
    C():B1(10),B2(20){cout<<"C"<<endl;}
}
/*output:
    B2:20
    B1:10
    B1
    B2
    C
*/

构造子类实例过程中,依次进行如下构造:

  • 构造基类(即B2 B1)
  • 构造当前派生类的成员对象(即memberb1 memberb2)
  • 构造当前派生类(执行自己的构造函数)(即C)

第三种:对当前对象属性使用初始化成员列表

当前对象属性就是  成员对象

class C:public B2, public B1
{
    private:
    int x;
    B1 memberb1;
    B2 memberb2;
    public:
    C(int x,int y):B1(10),B2(20),memberb1(1),memberb2(2){cout<<"C"<<lenl;}
}
/*output:
    B2:20
    B1:10
    B1:1
    B2:2
    C
*/

和基类很相似。

  • 在成员初始化列表,如果不显式调用成员对象的构造函数,程序就会调用默认构造函数。显式调用,程序就会调用你指定的构造函数。
  • 成员对象之间的构造顺序之和声明顺序有关,和在Member Initialization List中的顺序无关。
  • 当然,也可以不指定初始化列表,在构造函数中再进行成员对象的赋值,这会导致成员对象被构造多次。 更重要的是,因为常量类型、引用类型的成员不接受赋值,它们只能在初始化列表中进行初始化。

第四种:虚基类

#include "iostream.h"
class OBJ1
{
    public:
    OBJ1(){cout<<"OBJ"<<endl;}
}
class OBJ2
{
    public:
    OBJ2(){cout<<"OBJ2"<<endl;}
}
class BASE1
{
    public:
    BASE1(){cout<<"BASE1"<<endl;}
}
class BASE2
{
    public:
    BASE2(){cout<<"BASE2"<<endl;}
}
class BASE3
{
    public:
    BASE3(){cout<<"BASE3"<<endl;}
}

class BASE4
{
    public:
    BASE4(){cout<<"BASE4"<<endl;}
}
class DERIVER :public BASE1,vitural public BASE2
              public BASE3,virtual public BASE4
{
    public:
    DERIVER():BASE4(),BASE3(),BASE2(),BASE1(),obj2(),obj1(){cout<<"DERIVER"<<endl;}
    protect:
    OBJ1 obj1;
    OBJ2 obj2;
}
/*output
    BASE2
    BASE4
    BASE1
    BASE3
    OBJ1
    OBJ2
    DRIVER
*/


  • DERIVER的虚基类BASE2和BASE4最先构造,所以先输出了BASE2和BASE4,尽管它们在DERIVER类中的顺序不在最前面。
  • 然后在构造DERIVER的非虚基类,虽然它们排在前面,但是要优先构造虚基类,所以放在了虚基类后面。
  • 再构造DERIVER的对象obj1和obj2.它们以类定义时,数据成员排在前面的先构造;
  • 最后构造DERIVER本身。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值