IT辅导娱乐网| 蜘蛛地图| 所有文章|
C++虚继承时的内存布局详解 - IT辅导
  • 首页
  • IT技术 IT辅导资源网设计图
    • DVWA靶场
    • sqli-lab靶场
  • 源码基地
  • 软件分享 IT辅导资源网设计图
    • 辅助软件
  • emlog教程
  • 白嫖活动
  • 网络技巧 IT辅导资源网设计图
    • seo教程
  • 编程教程
  • 值得看一看 IT辅导资源网设计图
    • 值得听一听
    • 读懂世界
    • 活动线报
  • 更多功能 IT辅导资源网设计图
    • 在线投稿
    • 公告动态
    • 广告合作
    • 匿名投稿


登录后,享受更多优质服务哦
IT辅导资源网站长qq头像
欢迎回来,可爱的会员!个人中心退出登录
导航菜单
  • 首页
  • IT技术
    • DVWA靶场
    • sqli-lab靶场
  • 源码基地
  • 软件分享
    • 辅助软件
  • emlog教程
  • 白嫖活动
  • 网络技巧
    • seo教程
  • 编程教程
  • 值得看一看
    • 值得听一听
    • 读懂世界
    • 活动线报
  • 更多功能
    • 在线投稿
    • 公告动态
    • 广告合作
    • 匿名投稿

C++虚继承时的内存布局详解

2020/4/1 五年级扛把子  IT技术

首先

虚继承和虚函数是完全无相关的两个概念。


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


虚继承可以解决多种继承前面提到的两个问题:

虚继承底层实现原理与编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间,4字节)和虚基类表(不占用类对象的存储空间)(需要强调的是,虚基类依旧会在子类里面存在拷贝,只是仅仅最多存在一份而已,并不是不在子类里面了);当虚继承的子类被当做父类继承时,虚基类指针也会被继承。


实际上,vbptr指的是虚基类表指针(virtual base table pointer),该指针指向了一个虚基类表(virtual table),虚表中记录了虚基类与本类的偏移地址;通过偏移地址,这样就找到了虚基类成员,而虚继承也不用像普通多继承那样维持着公共基类(虚基类)的两份同样的拷贝,节省了存储空间。


在这里我们可以对比虚函数的实现原理:他们有相似之处,都利用了虚指针(均占用类的存储空间)和虚表(均不占用类的存储空间)。

虚基类依旧存在继承类中,只占用存储空间;虚函数不占用存储空间。

虚基类表存储的是虚基类相对直接继承类的偏移;而虚函数表存储的是虚函数地址。


虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类(Virtual Base Class),


下面来举例说明虚继承时内存的布局:


#include <iostream>
using namespace std;
class A
{
protected:
	int a;
};
class B1:public A
{
protected:
	int b1;
};
class B2:public A
{
protected:
	int b2;
};
class C:public B1,public B2
{
public:
	int c;
};
int main()
{
	cout<<sizeof(A)<<endl;   //4
	cout<<sizeof(B1)<<endl;  //8
	cout<<sizeof(B2)<<endl;  //8
	cout<<sizeof(C)<<endl;   //20
	return 0;
}



这是普通继承,很明显,类 A, B1, B2, C 的 sizeof 为4, 8, 8,20,由于类B1 B2都继承了类A的数据成员,所以再加上自己的数据成员,sizeof就变成了20.

那么,我们再来看看虚继承下的内存情况:


#include <iostream>
using namespace std;
class A
{
protected:
	int a;
};
class B1:virtual public A
{
protected:
	int b1;
};
class B2:virtual public A
{
protected:
	int b2;
};
class C:public B1,public B2
{
public:
	int c;
};
int main()
{
	cout<<sizeof(A)<<endl;   //4
	cout<<sizeof(B1)<<endl;  //12
	cout<<sizeof(B2)<<endl;  //12
	cout<<sizeof(C)<<endl;   //24
	return 0;
}




我们可以看到,菱形继承体系中的子类在内存布局上和普通多继承体系中的子类有很大的不一样。对于类B1和B2,sizeof的值变成了12,除了包含类A的成员变量int a外还多了一个指针vbptr,类C除了继承B1、B2各自的成员变量int b1、int b2,还有共享的int a和自己的成员变量外,还有两个分别属于B、C的指针,所以类C的sizeof就变成了24.

那么类D对象的成员变量布局就便变成了:int a  int b1   int b2   vbptr    vbptr   int  c


那么我们还可以加以验证一下:

#include <iostream>
using namespace std;
class A
{
protected:
	//int a;   注释掉a
};
class B1:virtual public A
{
protected:
	//int b1;  注释掉b1
};
class B2:virtual public A
{
protected:
	//int b2;   注释掉b2
};
class C:public B1,public B2
{
public:
	int c;
};
int main()
{
	cout<<sizeof(A)<<endl;   //1
	cout<<sizeof(B1)<<endl;  //4
	cout<<sizeof(B2)<<endl;  //4
	cout<<sizeof(C)<<endl;   //12
	return 0;
}



此时在虚继承后,会多出两个vbptr指针,所以就变成了 1  4   4    12.


 点赞:3  打赏  分享  海报

  • 打赏支付宝扫一扫
  • 打赏微信扫一扫
  • 打赏企鹅扫一扫
结束语
温馨提醒:如有技术问题以及资源失效请联系站长 QQ89549822 进行反馈!!!
 您阅读本文耗时: 0小时02分35秒
热度:886° 发布时间:2020年4月1日

推荐:

标题:C++虚继承时的内存布局详解

链接: https://www.itfd.cn/post-127.html

版权:转载请注明来源于【IT辅导娱乐网】为原创

上一篇: ctf练习

下一篇: 转 PHP网站从Apache转移到Nginx后产生404错误的原因和解决办法

作者头像 作者名称 作者性别
五年级扛把子
联系作者 作者主页

热门推荐

1 VM虚拟机快照和克隆的区别
2 史上最详细VM虚拟机中的文件共享四种方法
3 支付宝当面付对接XUEIDC系统【教程】
4 PHP5秒盾防CC代码(网站通用代码)
5 win server2008 去除密码复杂性策略
6 关于文件上传中的00截断分析

评论列表

取消回复

  • 存档

    • 2020年9月(191)
    • 2020年8月(92)
    • 2020年7月(5)
    • 2020年6月(224)
    • 2020年5月(392)
    • 2020年4月(267)
    • 2020年3月(76)
    • 2019年3月(1)
    • 1970年1月(29)
  • 搜索

  • 热门文章

    • 神佑之路手游源码-附视频教程
    • 最新可用老王VPN2.22.15谷歌市场版,免费使用
    • 私藏的十个网站,不看后悔系列
    • 虚拟商品自动发货商城源码
    • 不吃苦、不奋斗,你要青春做什么?
  • 随机文章

      • java异常处理详解
        • IntelliJ IDEA(2019)创建java maven项目
          • svn服务端的基本使用
            • mpvue开发微信小程序(环境搭建)
              • vscode新建vue+elementUI项目
    提示信息

    SQL语句执行错误: SELECT COUNT(*) AS total FROM emlog_twitter
    Table 'itfd.emlog_twitter' doesn't exist

    «点击返回