【C++入门】多继承(菱形继承)及其二义性问题

1、二义性问题

1.1、示例代码

#include <iostream>
#include <string>

using namespace std;

class A
{
public:
	void speak(void);
};

class B
{
public:
	void speak(void);

};

class C:public A, public B
{
public:

};



int main(void)
{
	C variable;

	variable.speak();	//使用speak成员时存在二义性问题,编译报错

	//variable.A::speak();  //明确指定,没有歧义
	//variable.B::speak();	//明确指定,没有歧义
	
	return 0;
} 

void A::speak()
{
	cout << "A::speak" << endl;
}

void B::speak()
{
	cout << "B::speak" << endl;
}

1.2、代码分析

root@ubuntu:# g++ test.cpp -o app --std=c++11
test.cpp: In function ‘int main()’:
test.cpp:31:11: error: request for member ‘speak’ is ambiguous
  variable.speak();
test.cpp:15:7: note: candidates are: void B::speak()
  void speak(void);
test.cpp:9:7: note:                 void A::speak()
  void speak(void);
make: *** [all] Error 1

(1)在A和B类中存在同名的speak成员;
(2)C同时继承A和B两个类,此时C中存在两个不同命名空间但是同名的成员(speak),当C类的对象使用speak成员时,编译器不知道该使用A类的speak,还是B类的speak;

2、解决二义性的方法

(1)解决办法1:避免出现,让A和B的public成员命名不要重复冲突。但这个有时不可控。
(2)解决办法2:编码时明确指定要调用哪一个,用variable.A::speak()明确指定调用的是class A的speak而不是class B的
(3)解决办法3:在C中重定义speak,则调用时会调用C中的speak,A和B中的都被隐藏了;
补充:对C++的隐藏特性不清楚的可以查看博客:《【C++入门】访问权限管控和继承机制详解》

3、菱形继承问题

3.1、产生菱形继承问题的原因

在这里插入图片描述

(1)产生菱形继承的原因如上图,C继承A和B,但是A和B都继承Base类,于是A和B都各自有一份Base类的成员;
(2)当C继承A和B时,此时C中就有两份Base类的成员,于是就产生了歧义;如果C类中使用Base类的成员,就不知道使用A中的那份还是B中的那份;

3.2、示例代码

#include <iostream>
#include <string>

using namespace std;


class Base
{
public:
	int dataBase;

};

class A: public Base
{
public:
	int dataA;

};


class B: public Base
{
public:
	int dataB;
};

class C:public A,public B
{
public:
	int dataC;

};

int main(void)
{
	C param;

	param.dataBase;	//产生歧义

	return 0;
} 

3.3、示例代码分析

[root@]$ g++ main.cpp -o app --std=c++11
main.cpp: In function ‘int main()’:
main.cpp:39:8: error: request for member ‘dataBase’ is ambiguous
  param.dataBase;
        ^
main.cpp:10:6: note: candidates are: int Base::dataBase
  int dataBase;
      ^
main.cpp:10:6: note:                 int Base::dataBase
make: *** [all] Error 1

C类对象在使用dataBase成员时,不知道使用A类中的dataBase,还是B中的dataBase,产生歧义,于是编译报错;

3.4、虚继承解决菱形继承问题

3.4.1、示例代码

#include <iostream>
#include <string>

using namespace std;


class Base
{
public:
	int dataBase;

};

class A: virtual public Base	//virtual:表示虚继承
{
public:
	int dataA;

};


class B: virtual public Base	//virtual:表示虚继承
{
public:
	int dataB;
};

class C:public A,public B
{
public:
	int dataC;

};

int main(void)
{
	C param;

	param.dataBase = 1;

	cout << "param.dataBase=" << param.dataBase << endl;

	return 0;
}

使用virtual关键字,让A和B都虚继承Base类;

3.4.2、虚继承实现的原理

实现原理参考博客:《【C++入门】虚继承的实现原理》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在起飞的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值