在多继承时,基类与派生类之间,或基类之间出现同名成员时,将出现访问时的二义性(不确定性)——采用虚函数或同名隐藏规则来解决。
当派生类从多个基类派生,而这些基类又从同一个基类派生,则在访问此共同基类中的成员时,将产生二义性——采用虚基类来解决。
问题举例:
class A {
public:
void f();
};
class B {
public:
void f();
void g()
};
class C: public A, piblic B {
public:
void g();
void h();
};
如果定义:C c1;
则 c1.f() 具有二义性
而 c1.g() 无二义性(同名隐藏)
解决办法:
解决方法一:用类名来限定 c1.A::f() 或 c1.B::f() 解决方法二:同名隐藏 在C 中声明一个同名成员函数f(),f()再根据需要调用 A::f() 或 B::f()
虚基类:虚基类用于有共同基类的场合
声明:以virtual修饰说明基类 例:class B1:virtual public B
作用:主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题. 为最远的派生类提供唯一的基类成员,而不重复产生多次拷贝 注意: 在第一级继承时就要将共同基类设计为虚基类。
例:class B { public: int b; }; class B1: virtual public B { public: int b1; }; class B2: virtual public B { public: int b2; }; class C: public B1, public B2 { public: float d; };
下面的访问是正确的: C cobj; cobj.b;
例
#include <iostream>
using namespace std;
class Base0 { //定义基类Base0
public:
int var0;
void fun0() { cout << "Member of Base0" << endl; }
};
class Base1: virtual public Base0 { //定义派生类Base1
public: //新增外部接口
int var1;
};
class Base2: virtual public Base0 { //定义派生类Base2
public: //新增外部接口
int var2;
};
class Derived: public Base1, public Base2 { //定义派生类Derived
public: //新增外部接口
int var;
void fun() {
cout << "Member of Derived" << endl;
}
};
int main() { //程序主函数
Derived d; //定义Derived类对象d
d.var0 = 2; //直接访问虚基类的数据成员
d.fun0(); //直接访问虚基类的函数成员
return 0;
}
虚基类及其派生类构造函数:
建立对象时所指定的类称为最(远)派生类。 虚基类的成员是由最派生类的构造函数通过调用虚基类的构造函数进行初始化的。 在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中给出对虚基类的构造函数的调用。如果未列出,则表示调用该虚基类的默认构造函数。 在建立对象时,只有最派生类的构造函数调用虚基类的构造函数,该派生类的其他基类对虚基类构造函数的调用被忽略。