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++入门】虚继承的实现原理》;