1. 什么是多继承?
多继承就是一个子类有多个父类,如下代码示例。
class C:public A, public B
{
};
2. 多继承会导致二义性问题
(1)场景1:多继承的二义性
C多继承自A和B,则C中调用A和B的同名成员时会有二义性。
原因:C从A和B各自继承了一个同名(不同namespace域)成员,所以用C的对象来调用时编译器无法确定我们想调用的是哪一个。
//基类 A
class A{
public:
void set(int a);
};
//基类 B
class B{
public:
void set(int a);
};
//派生类 C
class C:public A, public B
{
}
// main.cpp
int main()
{
c.set(); //编译报错,set()有二义性,编译器不知其来自A还是来自B
}
解决方法:
解决办法1:避免出现,让A和B的public成员命名不要重复冲突。但这个有时不可控。
解决办法2:编码时明确指定要调用哪一个,用 c.A::func() 明确指定调用的是 class A 的 func 而不是 class B 的。
解决办法3:在 C 中重定义 func,则调用时会调用 C 中的 func,A 和 B 中的都被隐藏了。
(2)场景2:菱形继承问题
即A为祖类,B1:A, B2:A, C:B1,B2,此时用C的对象调用A中的某个方法时会有二义性。
分析:c.func()有二义性,c.A::func()也有二义性,但是c.B1::func()和c.B2::func()却没有二义性。
解决办法:和问题1中的一样,但是问题2更隐蔽,也更难以避免。
3. 虚继承解决菱形继承的二义性问题
菱形继承导致二义性问题,本质上是在孙子类C中有B1和B2中包含的2份A对象,所以有了二义性。
虚继承解决方案:让B1和B2虚继承A,C再正常多继承B1和B2即可。
class B1: virtual public A
{
// A::set
};
class B2:virtual public A
{
// A::set
};
class D:public B1, public B2
{
// B1,B2为虚继承A,则D继承B1, B2时,只会继承了一个A类的函数,C++天然地优化掉其中一个A类的函数
};
4. 虚继承的实现原理
虚继承的原理是:虚基类表指针vbptr和虚基类表virtual table
参考:https://blog.csdn.net/xiejingfa/article/details/48028491