版权声明:本文为博主原创文章,未经博主允许不得转载。
二义性问题
1.在继承时,基类之间、或基类与派生类之间发生成员同名时,将出现对成员访问的不确定性——同名二义性。
2.当派生类从多个基类派生,而这些基类又从同一个基类派生,则在访问此共同基类中的成员时,将产生另一种不确定性——路径二义性。
同名二义性
同名隐藏规则——解决同名二义的方法
当派生类与基类有同名成员时,派生类中的成员将屏蔽基类中的同名成员。
若未特别指明,则通过派生类对象使用的都是派生类中的同名成员;
如要通过派生类对象访问基类中被屏蔽的同名成员,应使用基类名限定(::)。
多继承同名隐藏举例
同名二义性的解决方法
解决方法一:用类名来限定c1.A::f() 或c1.B::f()
解决方法二:同名覆盖,再造接口在C 中再声明一个同名成员函数f(),该函数根据需要调用A::f() 或B::f()
路径二义性
为了解决路径二义性问题,引入虚基类。
–用于有共同基类的多继承场合(多层共祖)
声明
–以virtual修饰说明共同的直接基类
例:class B1: virtual public B
作用
–用来解决多继承时可能发生的对同一基类继承多次和多层而产生的二义性问题.
–为最远的派生类提供唯一的基类成员,而不重复产生个副本。
注意:
–在第一级继承时就要将共同基类设计为虚基类。
虚基类举例
class B { public: int b;};
class B1 : virtual public B { private: int b1;};
class B2 : virtualpublic B { private: int b2;};
class C: public B1, public B2{ private: float d;};
在子类对象中,最远基类成分是唯一的。于是下面的访问是正确的:
C cobj;
cobj.b;
使用最远基类成员原则
运行结果:
Member of B0
Press any key to continue
有虚基类时的构造函数的调用次序:
无论虚基类与产生对象的派生类相隔多远,首先调用虚基类的构造函数;
然后按继承次序调用直接基类的构造函数;
如果有包含的对象,再按声明次序调用所包含对象类的构造函数;
最后才是普通类型数据成员的初始化。
有虚基类时的构造函数举例
运行结果:
B0's constructor called
B1's constructor called
B2's constructor called
B0's constructor called
B1's constructor called
B0's constructor called
B2's constructor called
D1's constructor called
Member of B0
Press any key to continue
“二义性”的回顾
凡是编译器访问或调用时有多于一项的合法选择,这种会让编译器举棋不定的代码叫具二义性的代码。
二义性的发生场合:
1.带默认形参值的函数与同名的重载函数相遇时;
2.继承时的同名二义;
3.多层共祖的路径二义;
4.形实结合时的类型兼容;
运行结果:
fun(int)
fun(char)
fun(int)
fun(char)
Press any key to continue
5.用户自定义类型的转换时。
如
class B;
class A
{
public:
A (const B &) {} //构造函数
};
class B
{
public:
operator A ( ) const {} //类型转换函数
};
void fun ( const A &);
B b;fun ( b ); // 到底调用哪个函数? 类型转换函数还是构造函数
解决:1。给A的构造函数前加explicit ,关闭自动转换功能;2。不提供或不直接提供B类的转换函数。