1.
“倒三角”问题——同名二义性
#include "iostream"
using namespace std;
class Parent_f
{
public:
void show()
{
cout<<"This is Parent_f\n";
}
};
class Parent_m
{
public:
void show()
{
cout<<"This is Parent_m\n";
}
};
class Son:public Parent_f,public Parent_m
{
public:
void display()
{
cout<<"This is son\n";
}
};
int main()
{
Son son;
son.show();
son.display();
cout << "Hello world!" << endl;
return 0;
}
上面的代码中,2个父类派生一个子类,但两个父类中都有同名的成员函数。派生出的子类产生二义性问题,编译时会报:
error: request for member 'show' is ambiguous
解决方法:
(1)利用作用域限定符(::),用来限定子类调用的是哪个父类的show()函数
son.Parent_f::show();
(2)在类中定义同名成员,覆盖掉父类中的相关成员
class Son:public Parent_f,public Parent_m
{
public:
void display()
{
cout<<"This is son\n";
}
void show()
{
cout<<"show:This is son.\n";
}
};
2.
“菱形”问题——路径二义性
有最基类A,有A的派生类B、C,又有D同时继承B、C,那么若A中有成员a,那么在派生类B,C中就存在a,又D继承了B,C,那么D中便同时存在B继承A的a和C继承A的a,那么当D的实例调用a的时候就不知道该调用B的a还是C的a,就导致了二义性。
#include "iostream"
using namespace std;
class Grandpa
{
public:
int year_old;
};
class Parent_f:public Grandpa {};
class Parent_m:public Grandpa {};
class Son:public Parent_f,public Parent_m {};
int main()
{
Son son;
son.year_old = 10;
cout << "Hello world!" << endl;
return 0;
}
Grandpa为Parent_f和Parent_m的基类,而Son又继承Parent_f和Parent_m,当Son访问Grandpa的year_old时,会出现二义性错误.
解决方法:
(1)使用作用域限定符,指明访问的是哪一个基类的成员。
注意:不能是Grandpa作用域下限定,因为Son直接基类的基类才是Grandpa,纵使指明了访问Grandpa的成员的话,对于Son来说,还是模糊的,还是具有二义性。
(2)在类中定义同名成员,覆盖掉父类中的相关成员。
(3)虚继承、使用虚基类
教科书上面对C++虚基类的描述玄而又玄,名曰“共享继承”,名曰“各派生类的对象共享基类的的一个拷贝”,其实说白了就是解决多重多级继承造成的二义性问题。父类对祖父类的继承方式改为虚继承,那么子类访问自己从祖父类那里继承过来的成员就不会有二义性问题了,也就是将子类对象里的祖父类对象统一为一个,继承的只有一个祖父类对象,代码如下。
#include "iostream"
using namespace std;
class Grandpa
{
public:
int year_old;
void show()
{
cout << "year_old:" << year_old <<endl;
}
};
class Parent_f:virtual public Grandpa {};
class Parent_m:virtual public Grandpa {};
class Son:public Parent_f,public Parent_m {};
int main()
{
Grandpa grp;
Parent_f pa_f;
Parent_m pa_m;
Son son;
grp.year_old = 100;
pa_f.year_old = 55;
pa_m.year_old = 50;
son.year_old = 10;
grp.show();
pa_f.show();
pa_m.show();
son.show();
cout << "Hello world!" << endl;
return 0;
}
使用了虚基类的方法,是不是感觉简单方便多了呢