<C++略识>之多重继承、多继承、虚继承

问题:什么是多重继承?
定义三个类:人、士兵、步兵,则有:步兵->士兵->人,这样的关系称之为多重继承,写法如下:

class Person
{
};
class Soldier:public Person
{
};
class Infrantryman:public Soldier
{
};

问题:什么是多继承?
定义三个类:农民、工人、农民工,则有:农民工->农民,农民工->工人,这样的关系称之为多继承,写法如下:

class Farmer
{
};
class Worker
{
};
class Migrant:public Farmer, public Worker
{
};

问题:为什么要有虚继承?是为了解决什么问题?
现象:假如我们有类A是父类,类B和类C继承了类A,而类D既继承类B又继承类C(这种菱形继承关系)。当我们实例化D的对象的时候,每个D的实例化对象中都有了两份完全相同的A的数据。因为保留多份数据成员的拷贝,不仅占用较多的存储空间,还增加了访问这些成员时的困难,容易出错,而实际上,我们并不需要有多份拷贝。
针对这种情况,C++提供虚基类(virtual base class)的方法,使得在继承间接共同基类时只保留一份成员。
现在,将上述类A申明为虚基类,方法如下:

class A //声明基类A
{
   // 代码
};
class B: virtual public A //声明类B是类A的公用派生类,A是B的虚基类
{
  // 代码
};
class C: virtual public A //声明类C是类A的公用派生类,A是C的虚基类
{
  // 代码
};
class D: public B, public C //类D中只有一份A的数据
{
  // 代码
};

[注意]:虚基类并不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的。因为一个基类可以在生成一个派生类时作为虚基类,而在生成另一个派生类时不作为虚基类。
声明虚基类的一般形式为:class 派生类名: virtual 继承方式 基类名
即在声明派生类时,将关键字 virtual 加到相应的继承方式前面,经过这样的声明后,当基类通过多条派生路径被一个派生类继承时,该派生类只继承该基类一次,也就是说,基类成员只保留一次。
[注意]:为了保证虚基类在派生类中只继承一次,应当在该基类的所有直接派生类中声明为虚基类,否则仍然会出现对基类的多次继承。比如:在上面的菱形继承关系中,如果在派生类B和C中将类A声明为虚基类,而在派生类D中没有将类A声明为虚基类,则如果再有一个派生类E继承自D,则在E中虽然从类B和C路径派生的部分只保留一份基类成员,但从类D路径派生的部分还保留一份基类成员。
问题:如何对虚基类进行初始化呢?
如果在虚基类中定义了带参数的构造函数,而且没有定义默认构造函数,则在其所有派生类(包括直接派生或间接派生的派生类)中,通过构造函数的初始化列表对虚基类进行初始化。如下:

class A //声明基类A
{
    A(int i); //申明一个带有参数的构造函数
};
class B: virtual public A //A是B的虚基类
{
    B(int n):A(n){ }  //B类构造函数,在初始化列表中对虚基类A进行初始化
};
class C: virtual public A //A是C的虚基类
{
    C(int n):A(n){ }  //C类构造函数,在初始化列表中对虚基类A进行初始化
};
class D: public B, public C
{
    D(int n):A(n),B(n),C(n){ }  //D类构造函数,在初始化列表中对所有基类进行初始化
};

[注意]:在定义类D的构造函数时,与以往使用的方法有所不同。以往,在派生类的构造函数中只需负责对其直接基类初始化,再由其直接基类负责对间接基类初始化。现在,由于虚基类在派生类中只有一份数据成员,所以这份数据成员的初始化必须由派生类直接给出。如果不由最后的派生类直接对虚基类初始化,而由虚基类的直接派生类(如类B和类C)对虚基类初始化,就有可能由于在类B和类C的构造函数中对虚基类给出不同的初始化参数而产生矛盾。所以规定:在最后的派生类中不仅要负责对其直接基类进行初始化,还要负责对虚基类初始化。
有的读者会提出:类D的构造函数通过初始化表调了虚基类的构造函数A,而类B和类C的构造函数也通过初始化表调用了虚基类的构造函数A,这样虚基类的构造函数岂非被调用了3次?大家不必过虑,C++编译系统只执行最后的派生类对虚基类的构造函数的调用,而忽略虚基类的其他派生类(如类B和类C) 对虚基类的构造函数的调用,这就保证了虚基类的数据成员不会被多次初始化。

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值