编程语言
首页 > 编程语言> > C++学习笔记:多继承及其二义性问题、虚继承

C++学习笔记:多继承及其二义性问题、虚继承

作者:互联网

C++学习笔记:多继承及其二义性问题

1.多继承

多继承就是一个子类有多个父类。

在继承中,子类会继承父类的成员变量和成员函数:

class A	
{
public:
	int a;
	void print(void){cout<<"a = "<<this->a<<endl;}
};

class C:public A 
{};

int main(int argc,char**argv)
{
	C c;
	c.a=5;
	c.print();
	return 0;
}

输出:

a = 5

上面是单继承的情况,C类很好继承了A类的print()方法,多继承和单继承的原理、效果并无明显区别,但是多继承会导致二义性问题,来看这样一种情况,假如C类继承自A类和B类,且B类中也有一个print()方法,这个时候C该继承哪一个呢?

不妨写代码测试一下:

class A
{
public:
	int a;
	void print(void){cout<<"a = "<<this->a<<endl;}
};

class B
{
public:
	int b;
	void print(void){cout<<"b = "<<this->b<<endl;}
};

class C:public A,public B
{
	
};

int main(int argc,char**argv)
{
	C c;
	c.a=5;
	c.print();
	return 0;
}

结果是编译报错了,对于编译器来说,print()是模糊有歧义的:

main.cpp:98:4: error: request for member ‘print’ is ambiguous
  c.print();

多继承的二义性问题有2种情况。

2.多继承的二义性问题情况1

场景1:C多继承自A和B,则C中调用A和B的同名成员时会有二义性。

原因分析:C从A和B各自继承了一个同名(但是不同namespace域)成员,所以用C的对象来调用时编译器无法确定到底想调用的是哪一个。

解决办法:

总结:能解决,但是都没有很好的解决。

3.多继承的二义性问题情况2

场景2:菱形继承问题。即A为祖类,B1:A, B2:A, C:B1,B2,此时用C的对象调用A中的某个方法时会有二义性。

原因分析:c.print()有二义性,c.A::print()也有二义性,但是c.B1::print()c.B2::print()却没有二义性。

解决办法:和情况1中的一样,但是情况2更隐蔽,也更难以避免。

4.多继承的二义性问题情况总结

二义性就是歧义,好的情况表现为编译错误,不好的情况表现为运行时错误,最惨的情况表现为运行时莫名其妙.随着系统规模的变大和逻辑变复杂,难免出现二义性,这是系统自身带来的。

解决二义性问题不能靠写代码的人个人的细心和调试能力,而要靠机制,也就是编程语言的更高级语法特性。虚函数、虚继承、纯虚函数、抽象类、重写覆盖、多态等概念就是干这些事的。

5.虚继承解决菱形继承的二义性问题

5.1 虚继承怎么用

场景:菱形继承导致二义性问题,本质上是在孙子类C中有B1和B2中包含的2份A对象,所以有了二义性。

虚继承解决方案:让B1和B2虚继承A,C再正常多继承B1和B2即可。

class A
{
public:
	int a;
	void print(void){cout<<"a = "<<this->a<<endl;}
};

class B1:virtual public A
{
	//A::print()
};

class B2:virtual public A
{
	//A::print()
};

class C:public B1,public B2
{
	//B1::A::print()
	//B2::A::print()
};

虚继承就这么简单,就是为了解决菱形继承的二义性问题而生,和虚函数(为了实现多态特性)并没有直接关系。

5.2 虚继承的实现原理

虚继承的原理是:虚基类表指针vbptr和虚基类表virtual table

标签:二义性,继承,void,C++,B1,B2,print
来源: https://blog.csdn.net/PecoHe/article/details/113307845