C++ 对象的内存布局

一切以事实说话:

代码:

   1: #include <stdio.h> 

   2:  

   3: class A {

   4:   public:   

   5:     int a;

   6:     int b;  

   7:     int c;  

   8: };

   9:  

  10: int main(int argc, char** argv) {

  11:   A obj;

  12:   printf(" obj   :%p\n obj.a: %p \n obj.b: %p \n obj.c: %p\n" ,                                                          

  13:         &obj, &obj.a, &obj.b, &obj.c);

  14:   return 0;

  15: }

执行结果:

不同的机器执行的结果可能不同,但是从这里的出的一个结论是:

对象的地址是整个类的起始地址(也就是低地址)。其成员的地址顺序和其在类中声明的顺序有关系。

而对上面的代码稍加修改,增加一个虚函数。

   1: #include <stdio.h>

   2:  

   3: class A { 

   4:   public:

   5:     virtual void show() {}                                                                                               

   6:     int a;

   7:     int b;

   8:     int c;

   9: };

  10:  

  11: int main(int argc, char** argv) {

  12:   A obj;

  13:   printf(" obj   :%p\n obj.a: %p \n obj.b: %p \n obj.c: %p\n" ,

  14:         &obj, &obj.a, &obj.b, &obj.c);

  15:   return 0;

  16: }

测试结果:

这里是由于增加了一个虚函数表的指针(测试机器为64位系统,故指针为8个字节)。从这里可以看出,虚函数表指针在类的起始地址,这也是为了对于不同的类该地址的偏移相同。

   1: class X {

   2: };

   3: class Y {

   4:   public:

   5:     virtual void f() {};

   6: };

   7: class X1 : public virtual X {

   8: };

   9: class X2 : public virtual X {

  10: };

  11: class A1 : public X1, public X2 {

  12: };

  13: class X3 : public X {

  14: };

  15: class X4 : public X {

  16: };

  17: class A2 : public X3, public X4 {

  18: };

  19: class Y1 : public virtual Y {

  20: };

  21: class Y2 : public virtual Y {

  22: };

  23: class B1 : public Y1, public Y2 {

  24: };

  25: class Y3 : public Y {

  26: };

  27: class Y4 : public Y {

  28: };

  29: class B2 : public Y3, public Y4 {

  30: };

  31:  

  32: int main (int argc, char** argv) {

  33:   printf("sizeof(X) %lu\n", sizeof(X));

  34:   printf("sizeof(Y) %lu\n", sizeof(Y));

  35:   printf("sizeof(X1) %lu\n", sizeof(X1));

  36:   printf("sizeof(X2) %lu\n", sizeof(X2));

  37:   printf("sizeof(A1) %lu\n", sizeof(A1));

  38:   printf("sizeof(X3) %lu\n", sizeof(X3));

  39:   printf("sizeof(X4) %lu\n", sizeof(X4));

  40:   printf("sizeof(A2) %lu\n", sizeof(A2));

  41:   printf("sizeof(Y1) %lu\n", sizeof(Y1));

  42:   printf("sizeof(Y2) %lu\n", sizeof(Y2));

  43:   printf("sizeof(B1) %lu\n", sizeof(B1));

  44:   printf("sizeof(Y3) %lu\n", sizeof(Y3));

  45:   printf("sizeof(Y4) %lu\n", sizeof(Y4));

  46:   printf("sizeof(B2) %lu\n", sizeof(B2));

  47:   return 0;

  48: }        

执行结果:

上面的测试结果得出的结论:

  1. 空类的大小不是0,而是1,这样是提供一个占位符,这样由空类创建出的两个对象的地址就会不同,以作区分。
  2. 当类不是空的时候,该占位符就不需要了,类的大小就是类中成员所需的空间大小

注: 本想深入一探究竟,不过这部分和编译器有很大的关系,非朝夕可以搞定。先写这么多,再多做了解后再补充吧。

refer:

http://blog.csdn.net/haoel/article/details/3081328

http://blog.csdn.net/haoel/article/details/3081385

http://blog.chinaunix.net/uid-22535463-id-2749544.html

C++ 虚函数和多重继承的内存布局初探的更多相关文章

  1. vs查看虚函数表和类内存布局

    虚继承和虚基类 虚继承:在继承定义中包含了virtual关键字的继承关系:     虚基类:在虚继承体系中的通过virtual继承而来的基类,需要注意的是:class CSubClass : publ ...

  2. 如何使用C#调用C++类虚函数(即动态内存调用)

      本文讲解如何使用C#调用只有.h头文件的c++类的虚函数(非实例函数,因为非虚函数不存在于虚函数表,无法通过类对象偏移计算地址,除非用export导出,而gcc默认是全部导出实例函数,这也是为什么 ...

  3. C++中虚函数继承类的内存占用大小计算

    计算一个类对象的大小时的规律: 1.空类.单一继承的空类.多重继承的空类所占空间大小为:1(字节,下同): 2.一个类中,虚函数本身.成员函数(包括静态与非静态)和静态数据成员都是不占用类对象的存储空 ...

  4. 从零开始学C++之虚继承和虚函数对C++对象内存模型造成的影响

    首先重新回顾一下关于类/对象大小的计算原则: 类大小计算遵循结构体对齐原则 第一个数据成员放在offset为0的位置 其它成员对齐至min(sizeof(member),#pragma pack(n) ...

  5. Vc++内存布局

    Vc++内存布局 测试平台 Windows server 2012 R2 and visual studio 2013 professional. 本篇文章意在介绍vc++中类的内存布局方式,只是研究 ...

  6. HotSpot源码分析之C++对象的内存布局

    HotSpot采用了OOP-Klass模型来描述Java类和对象.OOP(Ordinary Object Pointer)指的是普通对象指针,而Klass用来描述对象的具体类型.为了更好理解这个模型, ...

  7. c++ 对象内存分配和虚函数

    1. c++类对象(不含虚函数)在内存中的分布 c++类中有四种成员:静态数据.非静态数据.静态函数.非静态函数. 1. 非静态数据成员放在每个对象内部,作为对象专有的数据成员 2. 静态数据成员被抽 ...

  8. 浅析GCC下C++多重继承 & 虚拟继承的对象内存布局

    继承是C++作为OOD程序设计语言的三大特征(封装,继承,多态)之一,单一非多态继承是比较好理解的,本文主要讲解GCC环境下的多重继承和虚拟继承的对象内存布局. 一.多重继承 先看几个类的定义: 01 ...

  9. 虚函数列表: 取出方法 // 虚函数工作原理和(虚)继承类的内存占用大小计算 32位机器上 sizeof(void *) // 4byte

    #include <iostream> using namespace std; class A { public: A(){} virtual void geta(){ cout < ...

随机推荐

  1. 5G如何让智能手机再次变得丑陋?

    第一批5G移动终端将于明年到货,这意味着智能手机制造商现在正在研究细节.与过去十年智能手机所看到的很多其他组件改进不同,像更好的相机,更快的处理器和更亮的屏幕,5G无线电将需要一些设计上的妥协,而且看 ...

  2. 【leetcode】1022. Sum of Root To Leaf Binary Numbers

    题目如下: Given a binary tree, each node has value 0 or 1.  Each root-to-leaf path represents a binary n ...

  3. php str_pad()函数 语法

    php str_pad()函数 语法 str_pad()函数怎么用? php str_pad()函数用于把字符串填充到指定长度,语法是str_pad(string,length,pad_string, ...

  4. 使用Echarts中遇到值得记录的小案例(一)

    需求部分 在开发项目的时候遇到一个需求,就是如何保证echarts图表里至少显示一个图例的数据(也就是最后一个图例不能变成unselected的状态)下图是最初加载时的画面 不想出现图例都被点击取消导 ...

  5. 父元素a标签的href默认行为以及子元素绑定的click事件的响应之间存在影响

    原文地址 背景 开发过程中遇到问题,简单写个demo 运行环境为Chrome 68 描述一下这个问题,当a标签内部存在嵌套时, 父元素a标签的href默认行为以及子元素绑定的click事件的响应之间存 ...

  6. python中socket理论

    Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单 ...

  7. 用maven搭建多模块项目

    首先,前面几次学习已经学会了安装maven,如何创建maven项目等,最近的学习,终于有点进展了,搭建一下企业级多模块项目. 好了,废话不多说,具体如下: 首先新建一个maven项目,pom.xml的 ...

  8. Java JsonPath grab InvalidPathException in code, you must be catching Java 7's java.nio.file.InvalidPathException instead of JsonPath's com.jayway.jsonpath.InvalidPathExceptio

    I am using JsonPath and am able to parse my data and get the values when the path provided is correc ...

  9. jenkins构建后操作archive the artfacts的用法

    参考: https://blog.csdn.net/liqiangeastsun/article/details/79062806 Jenkins构建完成存档 Archive the artifact ...

  10. java构造器内部多态方法

    public class TestC { public static void main(String []args) { new Graph(5); }}class Grp{ void draw() ...