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

Posted 正在起飞的蜗牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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++入门】虚继承的实现原理》

推荐

我会在C++专栏持续根据更新C++相关的知识点,这里也给大家推荐一款学习C++的神器,我也是在用这一款神器在学习C++。
链接:学习神器跳转
如果你是想入门C++这门语言或者是找C++岗位的工作,都推荐你试试这个网站,里面有针对C++知识点的选择题、编程题,更有C++岗位的面试题,还可以在里面交流行业信息

以上是关于C++入门多继承(菱形继承)及其二义性问题的主要内容,如果未能解决你的问题,请参考以下文章

C++菱形继承问题与虚拟继承原理

C++菱形继承问题与虚拟继承原理

关于虚拟继承及其解决的问题

菱形继承的内部实现方式

继承(C++)

继承(C++)