一.基本概念
1.要使这个公共基类在派生类中只产生一个子对象,必须对这个基类声明为虚继承,使这个基类成为虚基类。
2. 虚基类用于有共同基类的场合
3. 声明虚基类的一般形式为:
class 派生类名: virtual 继承方式 基类名
例:class B1:virtual public B
5. 注意:
虚基类并不是在声明基类时声明的,而是在声明派生类时,指定继承
方式时声明的。因为一个基类可以在派生一个派生类时作为虚基类,而
在派生另一个派生类时不作为虚基类。
在第一级继承时就要将共同基类设计为虚基类
5.作用
1)主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义
性问题。
2)为最远的派生类提供唯一的基类成员,而不重复产生多次拷贝。
6.
例.虚继承的测试
#include<iostream>
using namespace std ;
class A
{ public :
A ( ) { cout << "class A" << endl ; }
} ;
class B : public A
{ public :
B ( ) {cout << "class B" << endl ; }
} ;
class C : public A
{ public :
C ( ) {cout << "class C" << endl ; }
} ;
class D : public B , public C
{ public :
D ( ) {cout << "class D" << endl ; }
} ;
int main ( )
{ D dd ; }
二.虚基类及其派生类构造函数
1.虚基类的成员是由最(远)派生类的构造函数通过调用虚基类的构造函数进行初始化的。
建立对象时所指定的类称为最(远)派生类。
2.在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中给出对虚基类的构造函数的调用。如果未列出,则表示调用该虚基类的默认构造函数。
3.在建立对象时,只有最(远)派生类的构造函数调用虚基类的构造函数,该派生类的其他基类对虚基类构造函数的调用被忽略。
例.有虚基类时的构造函数举例
#include <iostream>
using namespace std;
class B
{
public:
B(int n)
{
nV=n;
}
int nV;
void fun()
{
cout<<"Member of B"<<endl;
}
};
class B1: virtual public B
{
public:
B1(int a) : B(a) {}
int nV1;
};
class B2: virtual public B
{
public:
B2(int a) : B(a) {}
int nV2;
};
class D1: public B1, public B2
{
public:
D1(int a) : B(a), B1(a), B2(a) {}
int nVd;
void fund()
{
cout<<"Member of D1"<<endl;
}
};
int main()
{
D1 d1(1);
d1.fun();
return 0;
}
三.赋值兼容规则
赋值兼容规则指在程序中需要使用基类对象的任何地方,都可以用公有派生类的对象来替代。
赋值兼容规则中所指的替代包括以下的情况:
1.派生类的对象可以赋给基类对象(强制类型转换)
2. 派生类的对象可以初始化基类的引用
3.派生类的对象的地址可以赋给基类类型的指针
其特点
1.在替代之后,派生类对象就可以作为基类的对象使用,但只能使用从基类继承的成员。
2.一个派生类对象也是一个基类对象,一个基类对象可派上用场的地方,派生类对象一样可派上用场。反之则不然。
注意:
1.声明为指向基类的指针可以指向它的公有派生类的对象,但不允许指向它的私有派生类的对象。
例如:
class B {…};
class D:private B {…};
B b1,*pbl;D d1;
pb1=&b1; //合法,基类B的对象b1和B类的指针
pb1=&d1; //非法,不允许将基类指针指向它的私有派生类对象
2.允许将一个声明为指向基类的指针指向其公有派生类对象,但是不能将一个声明为指向派生类对象的指针指向其基类的一个对象。
3. 声明为指向基类对象的指针,当其指向公有派生类对象时,只能用它来直接访问派生类中从基类继承来的成员,而不能直接访问公有派生类的定义的成员。