虚继承是在多继承中为了解决冲突而技术。学术一点来讲,是指一个指定的基类,在继承体系结构中,将其成员数据实例共享给也从这个基类直接或间接派生的其余类。c++
虚继承很是有用,能够避免多继承的歧义和多重拷贝。函数
考虑有以下继承结构。学习
B和C继承A,D多继承B、C,咱们看如下代码。code
class A { public: virtual void sayHi(); }; class B :public A { public: virtual void onlyB(); }; class C :public A { public: virtual void onlyC(); }; class D :public B, public C { };
到这里,可能聪明的读者已经看出来有什么问题了。若是咱们对D进行实例化。对象
D d; A& a = d;
这么写的话,编译器会无情的报错。例如VS2019就会说这是一种不明确的转换。没错,由于按照上面的定义,D是一个有歧义的类。由于D间接地继承了两次A(B继承了,C继承了,D又继承了B和C),因此全部的D对象就会有两个不一样的由A派生的派生对象(B和C)。所以,尝试直接对其进行引用,编译器会一头雾水,这个引用究竟是想指向哪一个A啊?到底是 B::A 仍是 C::A ?因此这样是不对的。blog
固然,咱们可使用static_cast进行强制类型转换,可是这不是咱们今天学习的目标。继承
咱们能够看到,咱们不须要两个A,不须要A被继承两次。咱们只是须要一个层次结构来讲明A、B、C、D之间的关系。假如A是职业,B是销售,C是经理,咱们仅仅想表示D是一个销售经理。而不意味着D是两个A,销售经理是一种职业而不是两种职业。并且从上面这个特殊的例子来看,B和C并无重载sayHi()这个函数,sayHi()继承到D这里还是以前那套运做规律,因此咱们也不须要两份如出一辙的sayHi()。编译器
因而,虚继承便横空出世来解决这个问题了。编译
咱们若是这么声明继承,ast
class A { public: virtual void sayHi(); }; // virtual class B :public virtual A { public: virtual void onlyB(); }; class C :virtual public A { public: virtual void onlyC(); }; class D :public B, public C { };
若是在继承的类以前加上一个virtual关键词,表明该继承是虚继承。这样 B::A 和 C::A 如今是一个A了。这样,D中有且仅有一个共享的A。至关于间接派生类D直接穿透它的基类B和C,直接继承了A。这样,若是再建立A对D的引用,也不会有歧义了。由于只存在一种能够转换路径,那就是直接由A到D。
这个A就是所说的虚基类。因为虚基类是多个派生类共享的基类,所以必须明确到底谁来初始化这个虚基类。C++标准规定,由最后派生的类来初始化虚基类。所以,对于间接继承了虚继类的类,也必须能直接访问虚继承来的祖先类,可以访问其虚函数表。
例如,以前的例子当中,B和C、D的构造函数初始化列表中均可以给出虚基类的初始化,可是只能由D的构造函数执行虚基类的初始化。