菱形继承引入的问题
- 造成公共父类在子对象中存在多个实例
菱形继承的解决
- 采用虚继承
虚继承的逻辑
- 被虚继承的类会变成虚基类,虚基类在子类对象中存放在vbtable中,原本应该存储该父类对象的位置,替换为cbptr,vbptr指向vbtable中虚基类实例的位置,保证虚基类在子类对象中只有一个实例的存在
- 注意:虚基类在子类构造时会被当做子类的直接父类进行构造。需要在子类的初始化列表中初始化虚基类的产生列表
菱形继承
class A
{
public:
int a;
int funa()
{
cout << "A::funa()" << endl;
}
};
class B:public A
{
public:
int b;
int funb()
{
cout << "B::funb()" << endl;
}
};
class C :public A
{
public:
int c;
int func()
{
cout << "C::func()" << endl;
}
};
class D :public B,public C
{
public:
int d;
int fund()
{
cout << "D::fund()" << endl;
}
};
int main()
{
D dd;
return 0;
}
不合理的地方
- D对象中会有2个A的作用域
查看类布局的方式:使用命令 cl
步骤1:隐藏头文件
- 步骤2:
2.1打开源文件所在地
2.2shift+鼠标右键+打开Powershell窗口
- 步骤3:
输入命令:
菱形继承的构造
class A
{
public:
A(int a)
{
_a = a;
cout << "A::析构" << endl;
}
int _a;
int funa()
{
cout << "A::funa()" << endl;
}
};
class B:public A
{
public:
B(int a, int b)
:A(a)
{
_b = b;
cout << "B::析构" << endl;
}
int _b;
int funb()
{
cout << "B::funb()" << endl;
}
};
class C :public A
{
public:
C(int a, int c)
:A(a)
{
_c = c;
cout << "C::析构" << endl;
}
int _c;
int func()
{
cout << "C::func()" << endl;
}
};
class D :public B,public C
{
public:
D(int a1,int a2,int b,int c,int d)
:B(a1,b),C(a2,c)
{
_d = d;
cout << "D::析构" << endl;
}
int _d;
int fund()
{
cout << "D::fund()" << endl;
}
};
虚继承
- 继承权限前加了virtual的继承方式称为虚继承
class A
{
public:
int a;
int funa()
{
cout << "A::funa()" << endl;
}
};
class B:virtual public A
{
public:
int b;
int funb()
{
cout << "B::funb()" << endl;
}
};
class C :virtual public A
{
public:
int c;
int func()
{
cout << "C::func()" << endl;
}
};
class D :public B,public C
{
public:
int d;
int fund()
{
cout << "D::fund()" << endl;
}
};
int main()
{
D dd;
cout << dd.a << endl;
return 0;
}
虚基类
- 被虚继承的类称为虚基类
虚继承构造
虚继承的作用
虚基类作为父类在子类中被构造时是被放在vbtable中的。原本该存放该虚基类对象的地方被替换成了vbptr,vbptr就指向vbtable中虚基类对象的位置。此时就保证了在子类对象中只有一份虚基类对象。虚继承最主要的目的就是解决菱形继承带来的调用不明确问题。