一、什么是二义性
在多继承的场景里,当父类中存在同名变量时,子类访问父类的同名变量,将出现二义性,因为编译器不知道你将要访问的是哪个父类中的变量。
举个例子:
class A
{
public:
int a; // B1,B2 都将继承一个变量 a
};
class B1 : public A
{
};
class B2 : public A
{
};
class C : public B1, public B2
{
};
int main()
{
C c;
c.a = 10; // ERROR ! 二义性 !!!
return 0;
}
二、怎么解决
- 不使用多继承
一般来说,单继承就可以满足我们 99% 的需求了,我们应该尽量避免使用多继承带来的二义性问题。(注意:这里说的单继承不包括下面说的这种类似于 “接口” 的父类)。
由于 C++ 中不存在接口,但是可以使用只包含纯虚函数的抽象类替代,如果是只包含纯虚函数的抽象类,再多继承都将不会发生二义性(父类都没有变量了当然不会有二义性)。
- 使用虚继承
虚继承只能解决多个父类的同名变量都是从公共基类中继承而来的情况,就是下图这种:
使用虚继承:
class A
{
public:
int a;
};
class B1 : virtual public A // 虚继承
{
};
class B2 : virtual public A // 虚继承
{
};
class C : public B1, public B2
{
};
int main()
{
C c;
c.a = 10; // OK,不会有二义性了
return 0;
}
原理:使用虚继承时,C++ 编译器会做特殊处理,只会调用一个公共基类 A 的构造方法,这样就不会创建出多个同名变量 a 了。
- 使用 “类名::变量名” 显性访问
还有一种二义性出现的场景,就是多个父类都是独立的,它们没有公共基类,这些独立的父类中存在同名变量的话,就不能使用虚继承来解决了,类似下图这样子:
这种情况,我们就只能使用 “类名::变量名” 显性访问,避免二义性了:
class B1
{
public:
int a;
};
class B2
{
public:
int a;
};
class C : public B1, public B2
{
};
int main()
{
C c;
c.B1::a = 10;
c.B2::a = 20;
return 0;
}
同样,如果父类还存在同名方法,我们也可以使用 “类名::方法名” 这样显性调用。
————————————————
版权声明:本文为CSDN博主「阿飞__」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/afei__/article/details/82141731
来源:CSDN
作者:qq_23485187
链接:https://blog.csdn.net/qq_23485187/article/details/103814864