C++中虚拟继承的概念
为了解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样不仅就解决了二义性问题,也节省了内存,避免了数据不一致的问题。
比如类B会继承A的数据,类C也继承A的数据,那么这时候类D再继承B和C的话,就会在类D中存在两份A的拷贝 。这是绝对不允许的 。一是浪费空间,二是存在二义性
class 派生类名:virtual 继承方式 基类名virtual是关键字,声明该基类为派生类的虚基类。
在多继承情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧跟其后的基类起作用。
声明了虚基类之后,虚基类在进一步派生过程中始终和派生类一起,维护同一个基类子对象的拷贝。
语法:
Class C:virtual public A,virtual public B,…,virtual public n
{
}
执行顺序
1.执行虚基类的构造函数,多继承按照继承顺序构造
2.执行基类的构造函数,多继承按照继承顺序构造
3.执行成员对象的构造函数,多个成员对象按照申明顺序构造
4.执行派生类自己的构造函数
备注:执行析构的顺序与以上顺序相反
在执行虚基类构造函数的时候,如果是多重继承
虚继承与普通继承的区别
普通继承: C继承A 表明C “is a”即苹果就是水果
虚继承: C虚继承A 表明C “has a”即苹果是水果,但是苹果也可以是手机,C有了一个调用A的vptr
#include <iostream>
using namespace std;class Parent
{
public:
Parent()
{
cout << "P 构造函数被调用" << endl;
}
public:
int a;
};
// 在继承时添加一个关键字: virtual ====> 虚继承
class Parent1 :virtual public Parent
{
public:
Parent1()
{
cout << "P1 构造函数被调用" << endl;
}
public:
int b;
};
class Parent2:virtual public Parent
{
public:
Parent2()
{
cout << "P2 构造函数被调用" << endl;
}
public:
int c;
};
class Child:public Parent1, public Parent2
{
public:
Child()
{
cout << "C 构造函数被调用" << endl;
}
public:
int d;
};
int main()
{
/*Parent1 pa;
Parent1 *p1 = &pa;
Parent *p = &pa;
printf ("p1 = %p\n", p1);
printf ("p = %p\n", p);
pa.a = 1;
pa.b = 2;*/
Child c;
c.a = 1;
c.b = 2;
c.c = 3;
c.d = 4;
return 0;
}