普通的继承中,子类的虚表是从父类拷贝过来的,子类新增加的特有的虚函数,会添加在这个虚表里。参考文章:CSDN
多继承
问:如果A1、A2中有相同的虚函数,覆盖谁的?
答案:覆盖A1的
多继承还存在一种特殊情况——菱形继承:即此时A1、A2有一个公共的父类。
菱形继承(钻石继承)
继承向上的二义性:
例:Base类中有属性m,我们在Base1的构造函数中将m的值改成2, 在Base2的构造函数中将m的值改成3,那么当Derived中想使用m时,我们取2还是取3?答案是不知道的,在程序中这种情况也是通过不了编译的。为了解决多继承中的菱形继承问题,下面介绍虚继承来解决这一问题。
虚继承
目的:主要解决多继承中的菱形继承问题
class A
{
public:virtual void vfun(){}
};
class B:virtual public A
{
public:virtual void vfun1(){}
};//B包含两个虚表
虚继承特性:
- 父类和子类在空间上一种倒置关系(与普通继承相比)
- 当子类有特有的虚函数时,会有自己的虚表,就会有自己的虚指针
- 子类存在指向虚基类(虚继承里面的基类)的虚基表,子类会有虚基表的指针vbptr,它指向这个虚基表,虚基表里面的内容是指向自己及虚基类的地址偏移量
- 对于虚基类的初始化由最底层的派生类负责
虚继承解决菱形继承问题方案
1.先虚继承,再多继承
2.先虚继承,再虚多继承
重点掌握虚继承特性及所占内存空间大小
#include<iostream>
using namespace std;class Base
{
public:Base(int i) { cout << "B()" << " "; }virtual void vfun() {}int a;
};
class Base1:virtual public Base
{
public:Base1(int i): Base(i) { cout << "B1()" << " "; }virtual void vfun1() {}int b;
};
class Base2 :virtual public Base
{
public:Base2(int i) : Base(i) { cout << "B2()" << " "; }virtual void vfun2() {}int c;
};
//1.先虚继承,再多继承
class Derived1 :public Base1, public Base2
{
public:Derived1(int i) :Base1(i), Base2(i), Base(i) { cout << "D1()" << " "; }virtual void vfun3() {}int d;
};
//2.先虚继承,再虚多继承
class Derived2 :virtual public Base1, virtual public Base2
{
public:Derived2(int i) :Base1(i), Base2(i), Base(i) { cout << "D2()" << " "; }virtual void vfun4() {}int e;
};
int main()
{//测试所占内存大小Derived1 d1(1);cout << sizeof(d1) << endl;//B() B1() B2() D1() 36Derived2 d2(1);cout << sizeof(d2) << endl;//B() B1() B2() D2() 44return 0;
}
如有问题,欢迎交流指正!