1、虚继承的概念
为了解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样不仅就解决了二义性问题,也节省了内存,避免了数据不一致的问题。
2、语法格式
class 派生类名:virtual 继承方式 基类名
virtual是关键字,声明该基类为派生类的虚基类。
例如:
class B
{/*...*/};
class B1:virtual public B
{/*...*/};
class B2:virtual public B
{/*...*/};
3、构造函数执行顺序
首先执行虚基类的构造函数,多个虚基类的构造函数按照被继承的顺序构造;
执行基类的构造函数,多个基类的构造函数按照被继承的顺序构造;
执行成员对象的构造函数,多个成员对象的构造函数按照申明的顺序构造;
执行派生类自己的构造函数;
析构以与构造相反的顺序执行;
注意:
1)从虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中都要列出对虚基类构造函数的调用。但只有用于建立对象的最派生类的构造函数调用虚基类的构造函数,而该派生类的所有基类中列出的对虚基类的构造函数的调用在执行中被忽略,从而保证对虚基类子对象只初始化一次。
2)在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数执行。
4、举例分析:
//============================================================================
// Name : ex.cpp
// Author : Gao_Xiong
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include<iostream>
using namespace std;
class B
{
public:
B(int x=10)
{
b=x;
cout<<"Constructor called :B\n";
}
~B()
{
cout<<"Destructor called:B\n";
}
int b;
};
class B1:virtual public B //虚继承类B
{
public:
B1(int x1=11,int y1=21):B(x1)
{
b1=y1;
cout<<"Constructor called:B1\n";
}
~B1()
{
cout<<"Destructor called:B1\n";
}
int b1;
};
class B2:virtual public B //虚继承类B
{
public:
B2(int x2=12,int y2=22):B(x2)
{
b2=y2;
cout<<"Constructor called:B2\n";
}
~B2()
{
cout<<"Destructor called:B2\n";
}
int b2;
};
class D:public B1,public B2
{
public:
D(int i=1,int j1=2,int j2=3,int k=4):B(i),B1(j1),B2(j2)
{
d=k;
cout<<"Constructor called:D\n";
}
~D()
{
cout<<"Destrutoe called:D\n";
}
int d;
};
void test()
{
D objD;
cout<<"objD.b="<<objD.b<<endl;
cout<<"objD.b1="<<objD.b1<<"\nobjD.b2="<<objD.b2<<"\nobjD.d="<<objD.d<<'\n';
B1 objB1;
cout<<"objB1.b="<<objB1.b<<"\nobjB1.b1="<<objB1.b1<<endl;
}
int main()
{
test();
return 0;
}
运行结果:
Constructor called :B
Constructor called:B1
Constructor called:B2
Constructor called:D
objD.b=1 //由D类调用虚基类B的构造函数
objD.b1=21 //使用直接基类的构造函数,忽略D类的调用
objD.b2=22
objD.d=4 //对自身数据初始化
Constructor called :B
Constructor called:B1
objB1.b=11
objB1.b1=21
Destructor called:B1
Destructor called:B
Destrutoe called:D
Destructor called:B2
Destructor called:B1
Destructor called:B