在C++中,我们会遇到virtual这个关键字,但是它有两种含义:虚函数和虚继承,它们两个是完全无相关的两个概念。

什么是虚继承

虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝。这将存在两个问题:其一,浪费存储空间;第二,存在二义性问题通常可以将派生类对象的地址赋值给基类对象,实现的具体方式是,将基类指针指向继承类(继承类有基类的拷贝)中的基类对象的地址,但是多重继承可能存在一个基类的多份拷贝,这就出现了二义性。

当一个基类被声明为虚基类后,即使它成为了多继承链路上的公共基类,最后的派生类中也只有它的一个备份。例如:

class CBase { };
class CDerive1:virtual public CBase{ };
class CDerive2:virtual public CBase{ };
class CDerive12:public CDerive1,CDerive2{ };

则在类CDerive12的对象中,仅有类CBase的一个对象数据

虚继承实现原理

虚继承底层实现原理与编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(任何类型的指针变量都是占用4个字节)和虚基类表(不占用类对象的存储空间)(需要强调的是,虚基类依旧会在子类里面存在拷贝,只是仅仅最多存在一份而已,并不是不在子类里面了);当虚继承的子类被当做父类继承时,虚基类指针也会被继承。
实际上,vbptr指的是虚基类表指针,该指针指向了一个虚基类表,虚表中记录了虚基类与本类的偏移地址;通过偏移地址,这样就找到了虚基类成员,而虚继承也不用像普通多继承那样维持着公共基类(虚基类)的两份同样的拷贝,节省了存储空间。

虚继承与虚函数的异同

相似之处:都利用了虚指针(均占用类的存储空间)和虚表(均不占用类的存储空间)。
不同之处:虚基类依旧存在继承类中,只占用存储空间;虚函数不占用存储空间。虚基类表存储的是虚基类相对直接继承类的偏移而虚函数表存储的是虚函数地址

#include<iostream>
using namespace std;class A  //大小为4
{
public:int a;
};
class B :virtual public A  //大小为12,变量a,b共8字节,虚基类表指针4
{
public:int b;
};
class C :virtual public A //与B一样12
{
public:int c;
};
class D :public B, public C //24,变量a,b,c,d共16,B的虚基类指针4,C的虚基类指针
{
public:int d;
};int main()
{A a;B b;C c;D d;cout << sizeof(a) << endl;cout << sizeof(b) << endl;cout << sizeof(c) << endl;cout << sizeof(d) << endl;system("pause");return 0;
}
//
//1 > class A    size(4) :
//1 > +-- -
//1 > 0 | a
//1 > +-- -
//1 >
//1 > class B    size(12) :
//1 > +-- -
//1 > 0 | {vbptr}
//1 > 4 | b
//1 > +-- -
//1 > +-- - (virtual base A)
//1 > 8 | a
//1 > +-- -
//1 >
//1 > B::$vbtable@:
//1 > 0 | 0
//1 > 1 | 8 (Bd(B + 0)A)
//1 > vbi:class  offset o.vbptr  o.vbte fVtorDisp
//1 >         A       8       0       4 0
//1 >
//1 > class C    size(12) :
//1 > +-- -
//1 > 0 | {vbptr}
//1 > 4 | c
//1 > +-- -
//1 > +-- - (virtual base A)
//1 > 8 | a
//1 > +-- -
//1 >
//1 > C::$vbtable@:
//1 > 0 | 0
//1 > 1 | 8 (Cd(C + 0)A)
//1 > vbi:class  offset o.vbptr  o.vbte fVtorDisp
//1 >         A       8       0       4 0
//1 >
//1 > class D    size(24) :
//1 > +-- -
//1 > 0 | +-- - (base class B)
//1 > 0  | | {vbptr}
//1 > 4  | | b
//1 > | +-- -
//1 > 8 | +-- - (base class C)
//1 > 8  | | {vbptr}
//1 > 12 | | c
//1 > | +-- -
//1 > 16 | d
//1 > +-- -
//1 > +-- - (virtual base A)
//1 > 20 | a
//1 > +-- -
//1 >
//1 > D::$vbtable@B@:
//1 > 0 | 0
//1 > 1 | 20 (Dd(B + 0)A)
//1 >
//1 > D::$vbtable@C@:
//1 > 0 | 0
//1 > 1 | 12 (Dd(C + 0)A)
//1 > vbi:class  offset o.vbptr  o.vbte fVtorDisp
//1 >         A      20       0       4 0
//1 >

[C++基础]虚继承实现原理相关推荐

  1. 继承详解(虚继承实现原理)

    继承的概念及定义 概念: ​ 继承机制是面向对象程序设计为了提高代码复用率的一种手段,它可以保持原类特性的基础上进行拓展,简单来说继承是类层次的复用. 接下来我们来看一个简单的继承 class Per ...

  2. 多重继承与虚继承编程实验

    多重继承与虚继承编程实验 基本知识 多重继承 多重继承下的类作用域 虚继承 构造函数与虚继承 关于本程序 示例代码 Animal_virtual_baseVers.h virt-inherit.cpp ...

  3. C++虚继承中的虚基类表

    虚继承主要解决多重继承会在子类中存在多份拷贝的问题,这不仅浪费空间,而且存在二义性. 在之前的 C++ 继承中已经说过虚继承基本概念,这里不再赘述.这篇文章主要探究虚继承的原理.文章中多处给出了类实例 ...

  4. C++虚继承与虚函数

    虚继承和虚函数是完全无相关的两个概念. 虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝.这将存在两个问题:其一,浪费存储空间:第二,存在二义性问题,通常可 ...

  5. 菱形继承,多继承,虚继承、虚表的内存结构全面剖析(逆向分析基础)

    // 声明:以下代码均在Win32_Sp3   VC6.0_DEBUG版中调试通过.. 在逆向还原代码的时候,必须得掌握了菱形继承,多继承,虚继承虚函数的内存虚表结构.所以,这篇文章献给正在学习C++ ...

  6. C++中虚函数工作原理和(虚)继承类的内存占用大小计算

    转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7883531 一.虚函数的工作原理       虚函数的实现要求对象携带额 ...

  7. C++虚继承中构造函数和析构函数顺序问题以及原理

    多重继承的问题:多个类B,C,-继承同一个类A导致如果X继承了B,C,-那么在X中将还有多个A中成员的拷贝,如果想要访问A中的成员如果不加名字空间将会导致二义性,这种拷贝大多是没有实际意义的,为了避免 ...

  8. C++虚继承的实现原理、内存分布、作用

    虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝.这将存在两个问题:其一,浪费存储空间:第二,存在二义性问题,通常可以将派生类对象的地址赋值给基类对象,实现 ...

  9. C++继承机制(三)——多继承、菱形继承、虚继承原理

    目录: C++继承机制(一)--基本语法.三种继承方式.继承哪些数据 C++继承机制(二)--继承中的构造和析构顺序.继承同名成员的处理方式 C++继承机制(三)--多继承.菱形继承.虚继承原理 本篇 ...

最新文章

  1. 何凯明团队又出新论文!北大、上交校友教你用ViT做迁移学习
  2. 时间序列数据的存储和计算 - 开源时序数据库解析
  3. 【数据竞赛】Kaggle秘技,用Sigmoid函数做回归问题!
  4. armbian安装图形桌面_Linux图形界面的搜索工具,比Windows强吗?
  5. Nginx的http块自定义服务日志
  6. 坚持做一件事情真的很不容易,首先必须要克服惰性!
  7. lass翻译_【专题讲座】政务翻译人才培训系列讲座(1)
  8. resolv.conf
  9. 我是如何使用wireshark软件的
  10. (算法)宝石升级问题
  11. 如何在开源社区贡献代码_在社区支持大量涌现之后,Biicode便开始开源
  12. 贾跃亭“站台”!乐视高调宣布回归:60余款新品发布,还将发布超级手机
  13. python scrapy框架 抓取的图片路径打不开图片_Python中Scrapy爬虫图片处理详解
  14. 迷你MVVM框架 avalonjs 学习教程6、插入移除处理
  15. 如何使用Python开发随机森林集成
  16. 李商隐和杜牧并称“小李杜”,他俩到底谁的成就高?
  17. 花在照顾子女上的时间对父亲自己的大脑具有可塑性?
  18. 屏蔽去除CSDN上图片轮播形式的百度推广广告-20190104更新
  19. 在Mac M1芯片下使用Android Studio模拟器
  20. 女巫的魔法-第12届蓝桥杯Scratch省赛3真题第2题

热门文章

  1. 使用 PHP PDO 创建登录和注册表单
  2. Python学习之路——12306爬票遇到的两个问题
  3. 国庆读书-20221009
  4. java 动态更新_java动态更新枚举类
  5. 周易六十四卦——恒卦
  6. Taro request 请求封装
  7. go实现ssh远程机器并传输文件
  8. 帆软(FineReport)下载及安装
  9. 2016.11.21回顾 卡方检验
  10. 广播、组播、点播的区别