C++ 虚基类表指针字节对齐模型

浅谈c++类内存布局 引入类的原因是为了解决三层继承,爷爷类重复存在的问题。大概操作如下:普通继承:当通过子类对象给爷爷类成员变量赋值时会出现二义性。继承:子类中只有一个爷爷类避免了二义性。只有对类的成员变量进行处理如赋值的时候,才会用到虚基类表–取其中的值用作偏移值,来进行类成员变量首地址的定位运算。 阅读详情

关于虚基类表指针/虚函数表指针这些类里面的“隐藏成员”在结构里面是如何进行字节对齐的这个问题困惑了我48个小时。虽然网上也有很多关于虚继承、虚函数表、虚基类等内存布局的一些文章,但是基本上谈的都是大致的布局,什么地方有什么,按照什么顺序来排放等这些泛泛而谈的东西,好像都没有把字节对齐方面考虑进去的文章,或许他们都没有考虑到一些复杂层次的类继承关系,从而字节对齐的问题也没有成为问题,也自然而然地会被忽略掉,或者得出错误的对齐规则结论。


也许是我一开始就走错了路,在错误中越走越远,尝尽了各种曲扭的解决方案来回波折。我原以为我对字节对齐的规则已经很熟悉了,而恰恰是这仅仅几个字节的东西却困惑了我两三天,所以我觉得有必要将这个东西单独写一篇笔记,以记录我的研究成果和各种憋屈的时光。我们的目标是,精确到每一个字节~!

 

在Windows 里面微软是使用了虚基类表的方式来实现类的虚继承的,简单来讲就是当有虚继承的时候会在类里面加入一个“隐藏成员”虚基类表指针,这个指针就是指向虚基类表的了。我们要讨论的就是这个隐藏成员的字节级别的布局,其他的不在这里讨论。从现在开始我会一步一步地让事情变得更加复杂。


先看下面这片代码。在这里我使用了一个空类K,不要被这个东西所迷惑,我使用这个空类的目的主要是为了让它产生虚基类表指针而又不引入虚基类成员变量,这样我就可以少叙述一些关于虚基类成员排放的东西,而将焦点聚集在引入的那个虚基类表指针之上。这个空类虽然有点特殊,但是在这里它其他的东西和正常的类一样,不要纠结这个。还有,代码我直接指定了对齐参数,是为了不引起混乱。


#include"stdafx.h"
#pragma pack(8)
class K{};
 
class B :virtual K{
public:
       int b;
       B() :b(0xbbbbbbbb){}
};
 
 
int _tmain(int argc, _TCHAR* argv[])
{
       B aa;
       return 0;
} 


我们可以在IDE下打断点,用内存查看窗口轻易地观察到对象bb的内存布局情况,这个大家基本上都应该猜测得到大致的布局,就是在类B的开始插入了一个隐藏成员,虚基类表指针,然后才到B的成员b,因为虚基类没有成员所以其他的就不需要理了,这就是我选空类的原因,少说点话~。在VS2013下我抓到的布局是这样的:




恩,和我们猜测的一样。先是放了虚基类表指针然后才到 B 的成员。看到这里我们视乎可以得出点小结论,就是加入的隐藏成员,虚基类表指针,就是相当于在类里面加入一个正常的指针成员变量一样,即可以把类B看成是这样的等价布局:

class B { void *vb_ptr; int b;}


这样的话字节对齐等各方面都还算是合理的。

那么我们小改一下看下能推翻这个模型么。我们在B里面加一个成员变量double。变成这样:

 

#include "stdafx.h"
#pragma pack(8)
class K{};
 
class B :virtual K{
public:
C++函数继承,类的大小 C++函数所占的大小?有函数的对象比没有函数的对象所占字节大小有区别吗?继承、函数继承中具体类大小的计算;构造函数里调用函数是实引用还是引用? 阅读详情

相关推荐

结合sizeof浅谈C++中的指针字节对齐

sizeof 、数组、字节对齐等。

还在升级中的程序猿 1749

一次讲清楚什么是指针与内存地址对齐

万字长文解释什么是内存,什么是指针

amwtke的专栏 1321

C++结构体字节对齐

C++中结构体字节对齐详解。在计算机中数据存储和传输以位(bit)为单位,每8个位bit组成1个字节(Byte)。32位计算机的字长为32位,即4个字节;对应的,64位计算机的字长为64位,即8个字节。计算机系统对本类型数据在内存中存放的位置有限制,要求这些数据的起始地址的值是某个数k的倍数,这就是所谓的内存对齐,而这个k则被称为该数据类型的对齐模数。

关注校招求职,微信号:job_campus 7631

C++继承产生的指针虚基类表函数产生的函数指针函数

本博客主要通过查看类的内容的变化,深入探讨有关指针的问题。 一、继承产生的虚基类表指针虚基类表 如下代码:写一个棱形继承,父类Base,子类Son1和Son2继承Base,又来一个类Grandson继承Son1和Son2。 代码: class Base { public: int a; protected: int b; private: int c; }; class Son1 :virtual public Base { public: int a; protected: i

yi_chengyu的博客 8563

指针对齐问题总结

通过上面几篇转载的文章,可以看到 1. 默认情况下char为1字节对齐,short为2自己对齐,int为4字节对齐 __packet为1字节对齐,struct默认为最长类型对齐 所以当进行指针强转时,如从char *p = xxx; int *p1= p; 此时p1得到的结果可能是有问题的,因为p1需要4自己对齐!!! 所以大家做指针强制转换时,一定要特别的小心! 2. stru

yazhouren的专栏 6149

C++对象模型_第四章_C++数据语义学

下面的方式打印成员变量指针。// 16printf("pmyobj->m_n偏移值 = %d\n", mypoint);由于类内存模型会遵循字节对齐,以4字节对齐为例,如果一个变量不满足4字节,编译器会对这个内存进行填充到4字节。下面代码,将小内存的变量char 如果连续定义完后,再定义int,总内存8字节;如果int在char中间定义,总内存12字节。int m_i1;char m_c2;char m_c3;

weixin_43916755的博客 973

C++ 对象内存模型

继承,封装,多态是面向对象的三大特性之一,以类为例,类分为数据成员和函数 而函数分为static、非static、virtual函数三大类函数,那么一般的C++对象其内存模型是如何。 类中存在部分: 成员变量 静态成员变量 成员函数 静态成员函数 构造函数 析构函数 函数 析构函数 纯函数 通常而言对于一个对象,其在内存中的模型不包含函数,只包含成员,而函数单独存放,所有对象通过地址进行调用。对象在内存模型及其占用大小受几方面因素影响: 成员变量 指针 虚基类表指.

一只老风铃 1838

[Boolan] C++第四周 homework 函数与内存对齐

参考链接:C++ 虚基类表指针字节对齐模型题目:分别给出下面的类型Fruit和Apple的类型大小(即对象size),并通过画出二者对象模型图以及你的测试来解释该size的构成原因。 声明:编译器是VC6.0对象模型图黑色部分是我没有找到什么官方文档来解释,但是找到一边博客,并且被CSDN的C++知识库收录,应该尤其权威性。隐藏成员的加入不能影响在其后的成员的对齐 #include <iostrea

a312024054的专栏 745

C++ 继承、指针虚基类表

当一个类有类时,编译器需要额外的指针来解析类的偏移,从而支持动态多态。的大小可能导致对齐问题(例如,它可能是 4 字节,而后续成员需要 8 字节对齐),编译器插入。计算所需的存储空间,并决定对象的内存分布,即便还没有实际分配对象。,明该类可能包含指针(通常为 8 字节,在 64 位系统上)和一些数据成员。生成,可用于分析 C++ 类的内存布局和拟继承机制的实现。这幅图片展示了 C++ 代码的编译结果,分析的是一个。的情况下,帮助对象正确解析类的存储位置。类的内存布局,并报告。

xinxin的博客 1200

C++ 虚基类表指针字节对齐

下面博客转载自别人的,我也是被这个问题坑了快两天了,关于各种类,继承,函数以及数据成员等引发的一系列内存对齐的问题再次详细描述 先看下面这片代码。在这里我使用了一个空类K,不要被这个东西所迷惑,我使用这个空类的目的主要是为了让它产生虚基类表指针而又不引入类成员变量,这样我就可以少叙述一些关于类成员排放的东西,而将焦点聚集在引入的那个虚基类表指针之上。这个空类虽然...

weixin_30550271的博客 74

c++字节对齐

什么是字节对齐 现代计算机中,内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量。但实际中在访问特定类型变量时经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序一个接一个地存放,这就是对齐。 二 对齐的原因和作用 不同硬件平台对存储空间的处理上存在很大的不同。某些平台对特定类型的数据只能从特定地址开始存取,而不允许其在内存中任意存放。例如Motorola 68000 处理器不允许16位的字存放在奇地址,否则会触发异常,因此在这种...

baidu_16370559的博客 5308

c++字节对齐(全)

一、类型字节数 系统平台 16位 32位 64位 char 1 1 1 short 2 2 2 int 2 4 4 unsigned int 2 4 4 float 4 4 4 double 8 8 8 long 4 4 8 unsigned long 4 4 8 long long 8 8 8 * 2 4 8

qq_30534935的博客 2760

C语言础 - 结构体类型字节对齐总结

一、什么是字节对齐 在计算机中,内存空间是按照字节(1B = 8 bit)划分的,每一个字节都有一个编号,这就是字节的地址。理论上可以从任意起始地址访问任意数据类型的变量,但在实际使用中,访问特定数据类型变量时需要在特定的内存起始地址进行访问,这就需要各种数据类型按照一定的规则在空间上进行排列,而不是顺序地一个接一个地存放,这就是字节对齐。 如果一个变量的内存起始地址正好是其数据类型长度的整数倍,就被称作自然对齐。比如,在32系统下,假设一个int型变量的起始地址为0x00000004,那它就是自然对齐

yunfan 6980

C/C++中数据大小字节对齐、内存占用总结

数据大小获取 sizeof()操作符,求占用空间,对数组而言大小为 type大小 * 数据个数; int a[] = {1,2,3,4,5} sizeof(a) = 20 sizeof(&a) = 4 特殊的:在string时,由于字符串本质上就是自带‘\0’结尾的 char[] 数组,而char 的大小有恰好为1, 因此sizeof()就正好会是数组的长度; 在C++98中是不允许对类的非静态成员变量使用sizeof()的,而在C++11中是合法的; 根据 C99 规定,size..

Mr_Xuf的博客 4044

C++字节对齐

希望通过本文全面记录并帮助读者理解字节对齐。计算机知识的学习不仅要知其然,更要知其所以然,知道为什么要这样设计,而不是死记硬背,才能领悟前任这样设计的思想,未来真正运用的时候才能融会贯通

Accepted_Lam的博客 2324

C/C++字节对齐规则

现代计算机中,内存空间按照字节划分,理论可以从任何骑术地址访问任意类型的变量。但是实际访问中特定类型的变量经常在特定的内存地址访问,这就需要各种类型数据按照一定规则在空间上排列,而不是一个接一个地存放,这就是对齐。

m0_51765675的博客 1042
上一篇: C/C++ 字节对齐
下一篇: C++ 无虚函数、无虚基类的继承内存模型
chengonghao
博客等级 码龄12年 491粉丝 475原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值