1、虚基类的概念,为什要有虚基类?
当派生类的多个基类有共同基类时,派生类继承而来的成员有相同名称,定义对象之后同名成员在内存中有多份数据成员和函数成员的拷贝,明显造成了内存浪费。
虚基类:将派生类直接基类的共同基类声明为虚基类。这样派生类从不同直接基类继承而来的同名数据成员在内存中就会只有一份拷贝(同名成员函数只有一个映射)。实现了唯一标识同名成员,也节省内存空间。
虚基类声明方式:
class 派生类名:virtual 继承方式 基类名
<pre><span style="font-family:Microsoft YaHei;"></span><pre name="code" class="cpp">#include<iostream>
using namespace std;
class Base0
{
public:
voidshow(){cout<<"x of Base0 "<<x<<endl;}
intx; //public,不然派生类无法访问
};
class Base1 : virtual public Base0 //Base0为虚基类,公有派生Base1类
//virtual和继承方式一样,只限定紧跟在它后面的类
{
};
class Base2 :virtual public Base0
{
};
class child:public Base1,public Base2
{
};
int main()
{
childd;
d.x=1; //数据成员x只有一份副本
d.show();
return0;
}
从上面我们可以看到,声明虚基类只需要在它的派生类声明时使用关键字virtual修饰。
2、虚基类派生类的构造函数
上面没有定义构造函数,所以使用了默认构造。当定义带参构造时,虚基类直接或间接被派生类继承,必须在派生类构造函数成员初始化列表中给出对虚基类成员的初始化。
#include<iostream>
using namespace std;
class Base0
{
public:
Base0(inty){x=y;}
voidshow(){cout<<"x of Base0 "<<x<<endl;}
intx; //public,不然派生类无法访问
};
class Base1 : virtual public Base0 //Base0为虚基类,公有派生Base1类
{
public:
Base1(inty):Base0(y){}
//必须在构造函数成员初始化列表中给出对虚基类成员的初始化
};
class Base2 :virtual public Base0
{
public:
Base2(inty):Base0(y){}
};
class child:public Base1,public Base2 //最远派生类
{
public:
child(inty):Base0(y),Base1(y),Base2(y){}
//由child构造函数调用Base0的构造函数来初始化,其他类的构造函数忽略
};
int main()
{
childd(1);
d.show();
return0;
}
上面代码中,我们可能会认为调用了三个类的构造函数,也就是x被初始化了三次。但事实并不是这样.
编译器特殊处理:如果构造的对象有从虚基类继承而来的成员,成员的初始化只由最远派生类的构造函数调用虚基类的构造函数来完成。上面child就是最远派生类,并由其构造函数调用Base0的构造函数完成,其他如Base1-2的被忽略。