虚基类、虚拟继承、虚函数?

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_39088557/article/details/80559997

  前几天师兄想考我什么是虚基类的时候,我说是因为多重继承中,如果出现菱形继承(multiple inheritance diamond),不想要末端派生类有两份最底层基类的数据的话,就得用虚拟继承。结果居然被怼了,说我说的啥玩意儿?我还以为我记错了,实际上是他把虚基类和含有虚拟函数的基类给混淆了。

  今天读了Effective CPP,再总结一下虚基类把,就是被虚拟继承的基类。虚拟继承很少用到,因为多重继承会很复杂,不推荐也不常用。离开了多重继承,虚拟继承就完全失去了存在的必要,因为虚拟继承会降低效率、占用更多的空间。

       效率上,在通过继承类对象访问虚基类对象中的成员(包括数据成员和函数成员)时,都必须通过某种间接引用来完成,这样会增加引用寻址时间(就和虚函数一样),其实就是调整this指针以指向虚基类对象,只不过这个调整是运行时间接完成的。

        空间上,由于共享所以不必要在对象内存中保存多份虚基类子对象的拷贝,这样较之多继承节省空间。虚拟继承与普通继承不同的是,虚拟继承可以防止出现菱形继承时,一个派生类中同时出现了两个基类的子对象。也就是说,为了保证这一点,在虚拟继承情况下,基类子对象的布局是不同于普通继承的。因此,它需要多出一个指向基类子对象的指针。

        考虑四种情况在vs2013(win32)中的sizeof(a),sizeof(b)

第一种情况:         第二种情况:          第三种情况            第四种情况:
class a           class a              class a              class a
{              {                {                 {
    virtual void func();  virtual void func();     virtual void func();        virtual void func();
};              };                  char x;              char x;
class b:public virtual a   class b :public a           };                };
{              {                class b:public virtual a      class b:public a
    virtual void foo();   virtual void foo();     {                 {
};              };                virtual void foo();        virtual void foo();
                               };                };

        前两种情况,a的大小是虚函数表指针所以sizeof(a)=4,后两种情况,多了个占1字节的char,内存对齐后,sizeof(a)=8。

        派生类里面要包含基类的空间,虚继承、虚函数表分别需要一个指针,所以第一种情况sizeof(b)=12,第二种情况是8,第三种情况是16,第四种情况是12。

        虚函数说白了就是一种动态的联编,主要是用于基类指针指向派生类对象的时候,能动态地选择对应的虚函数。虚函数相当于继承了一个接口,虚函数可以是纯虚函数,纯虚函数也可以有定义(有定义的纯虚函数,技能强制要求派生类重定义,防止误用基类的操作,又能提供缺省操作,不过需要在派生类中显示调用Base::virtualFun()),这都是后话,反正跟虚基类是另一个概念了。

        明白师兄的意思,但是从学术上来讲还是要严谨一点,虚基类和带虚函数的基类不一样。

猜你喜欢

转载自blog.csdn.net/sinat_39088557/article/details/80559997