一.单继承 –多态性
二.多继承- 二义性ambiguous
- 多个直接父类中 出现同名成员时产生的二义性
- 同一个父类 通过不同继承路径产生的二义性
例8-6 A1父类中的f1(),还是A2父类中的f1()
#include <iostream>
using namespace std;
class A1
{ public:
void f1()
{ cout<<"A1类中的函数f1()"<<endl; }
};
class A2
{ public:
void f1()
{ cout<<"A2类中的函数f1()"<<endl; } // 该成员与A1中的重名
};
class B:public A1,public A2
{
};
int main()
{
B b;
b.f1(); // 该句出错
}
#include <iostream>
using namespace std;
class A1
{ public:
void f1()
{ cout<<"A1类中的函数f1()"<<endl; }
};
class A2
{ public:
void f1()
{ cout<<"A2类中的函数f1()"<<endl; } // 该成员与A1中的重名
};
class B:public A1,public A2
{
};
int main()
{
B b;
b.A1::f1(); // 作用域运算符
b.A2::f1();
}
#include <iostream>
using namespace std;
class A1
{ public:
void f1()
{ cout<<"A1类中的函数f1()"<<endl; }
};
class A2
{ public:
void f1()
{ cout<<“A2类中的函数f1()”<<endl; // 该成员与A1中的重名 }
void f2()
{ cout<<"A2类中的函数f2()"<<endl; }
};
class B:public A1,public A2
{ public:
void f2()
{ cout<<"派生类B中的函数f2()"<<endl; } // 与基类A2中的成员同名
void f3()
{ cout<<"派生类B中的函数f3()"<<endl; }
};
void main()
{ B b;
b.f1(); // 该句出错
b.f2();
b.f3();
}
程序在编译时会出错,错误信息如下:
error C2385: 'B::f1' is ambiguous
warning C4385: could be the 'f1' in base 'A1' of class 'B'
warning C4385: or the 'f1' in base 'A2' of class 'B'
A1类中有一个函数成员f1(),A2类中也有一个同名的函数成员f1(),
派生类B中继承了这两个同名的成员,
类B的对象b对f1()的访问b.f1()出现了二义性,无法确定访问A1类中的f1(),还是A2类中的f1()?
解决方法:
使用作用域运算符“::”明确指出访问的是从哪个类中继承的成员。
例如:将b.f1()写成b.A1::f1();或b.A2::f1();
程序中,A2类和B类中还有一个同名的函数成员f2(),但b对f2的访问b.f2();在编译时并没有出错。
在类的继承层次结构中,基类和派生类具有包含关系,派生类在内层,基类在外层。
同名覆盖
具有包含关系的两个或多个作用域,如果在外层中声明的标识符在内层中没有同名标识符,则它在内层可见,如果内层中声明了同名标识符,则外层标识符在内层不可见,也就是内层标识符覆盖了外层的同名标识符
B类和A1类、B类和A2类都具有包含关系,对于B类和A2类,A2类在外层,B类在内层,这样,根据可见性原则,可知b.f2()访问的是B类的f2()。
void main()
{ B b;
b.A1::f1();
b.A2::f1();
b.f2();
b.f3();
}
这时,没有出现二义性
多层继承中 使用作用域运算符==延伸例8-7
#include <iostream>
using namespace std;
class A
{ public:
void fun()
{ cout<<"A类的函数fun()"<<endl; }
};
class B:public A
{ public:
void fun() { cout<<"B类的函数fun()"<<endl;}
};
class C:public B
{ public:
void fun() { cout<<"C类的函数fun()"<<endl; }
};
class D:public C
{ public:
void f() { C::fun(); B::fun(); A::fun(); }
};
void main()
{ D d;
d.f();
}
例8-8如果一个派生类C 从多个基类B1 B2派生,而这些基类又有一个共同的老基类A,当对该老基类A中说明的成员进行访问时,也可能出现的二义性
#include <iostream>
using namespace std;
class A
{ public:
void fun()
{ cout<<"A类的函数fun()"<<endl; }
};
class B1:public A
{ };
class B2:public A
{ };
class C:public B1,public B2
{ };
void main()
{ C c;
c.fun();
}
程序在编译时出错,错误信息如下:
error C2385: 'C::fun' is ambiguous
warning C4385: could be the 'fun' in base 'A' of base 'B1' of class 'C'
warning C4385: or the 'fun' in base 'A' of base 'B2' of class 'C'
图(b)中,类C继承两个基类B1和B2,而B1和B2又有一个共同的基类A,这样,类A是派生类C在两条继承路径上的公共基类,这个公共基类在派生类C的对象中将包含两个基类A的子对象,从而导致对基类成员访问时的不唯一性,
将基类A定义为虚基类,能够使得公共基类A在派生类中只产生一个子对象,就可避免二义性问题
法(一)作用域运算符
#include <iostream>
using namespace std;
class A
{ public:
void fun() { cout<<"A类的函数fun()"<<endl; }
};
class B1:public A { };
class B2:public A { };
class C:public B1,public B2 { };
main()
{ C c;
c.B1::fun();
c.B2::fun();
}
法(二)虚基类
#include <iostream>
using namespace std;
class A
{ public:
void fun() { cout<<"A类的函数fun()"<<endl; }
};
class B1:virtual public A { };
class B2:public virtual A { };
class C:public B1,public B2 { };
void main()
{ C c;
c.fun();
}