前言:
此文章仅作本人学习笔记留存分享。如有出错欢迎指正。
正文:
如果一个派生类从多个基类中派生,而这些基类又有一个共同的基类,则在这个派生类将保留共同基类的多份副本,如下图所示: 要让派生类只保留共同基类的一份副本,可以让这个 共同基类说明为虚基类 。 虚基类的定义格式为 : class 派生类 :virtual [ 继承方式 ] 基类名 代码示例class A //共同基类A
{
public:
int a;
void display(){cout<<"共同基类A中的a="<
运行结果如下:
虚基类的构造函数只能调用一次。直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中列出对虚基类的初始化。
注意:
- 虚基类的构造函数在所有非虚基类之前调用;
- 若同一层次中包含多个虚基类,这些虚基类的构造函数按它们说明的次序调用;
- 若虚基类由非虚基派生而来,则先调用基类构造函数,再调用派生类的构造函数
class N //共同基类的祖先
{
public:
N(){cout<<"共同基类的祖先——N类的构造函数"<
调用虚基类的构造函数的方法与调用一般基类的构造函数的方法不同:编译器约定,在执行派生类的构造函数时都不调用虚基类的构造函数,而是在最终派生类的构造函数中直接调用虚基类的缺省构造函数初始化虚基类的数据成员。因此,虚基类定义中一般要包含有缺省的构造函数。
class A{
public:
int x;
//A(int a=0){x=a;}
};
class B:virtual public A{
public:
int y;
B(int a=0, int b=0):A(b)
{y=a;} // 不调用虚基类的构造函数
void pb( ){cout<<"x="<
虚继承实现原理
虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝。这将存在两个问题:其一,浪费存储空间;第二,存在二义性问题,通常可以将派生类对象的地址赋值给基类对象,实现的具体方式是,将基类指针指向派生类(派生类有基类的拷贝)中的基类对象的地址,但是多重继承可能存在一个基类的多份拷贝,这就出现了二义性。
虚继承可以解决多种继承上面提到的两个问题。
虚继承底层实现原理与编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间,4字节)和虚基类表(不占用类对象的存储空间)(需要强调的是,虚基类依旧会在子类里面存在拷贝,只是仅仅最多存在一份而已,并不是不在子类里面了);当虚继承的子类被当做父类继承时,虚基类指针也会被继承。
虚基类依旧存在继承类中,只占用存储空间。
虚基类表存储的是虚基类相对直接继承类的偏移。
class A //内存大小为4
{ public: int a; };
class B :virtual public A //变量a,b共8字节,虚基类表指针4
{ public: int b; };
class C :virtual public A //与B一样12
{ public: int c; };
class D :public B, public C //24,变量a,b,c,d共16,B的虚基类指针4,C的虚基类指针4
{ public: int d; };
void main()
{ A a; B b;
C c; D d;
cout << "sizeof a:" << sizeof(a) << endl;
cout << "sizeof b:" << sizeof(b) << endl;
cout << "sizeof c:" << sizeof(c) << endl;
cout << "sizeof d:" << sizeof(d) << endl;
}



