一、类对象的sizeof

1、空类对象的sizeof

class test3{ };int main(int argc, char const *argv[])
{   test3 t;cout<<sizeof(t)<<endl;return 0;
}

C++规定,空类对象的sizeof是1,因为如果空类对象的sizeof是0,那么就意味着可以产生不占内存的代码,和计算机的原理违背。所以,编译器在编译代码时,会在test3中安插一个char数据。

向test3中添加一个函数

class test3
{void func() {}
};

输出结果同上,所以,类中的成员函数不占用内存空间

向test3中添加一个char成员

class test3
{void func() {}char a;
};

输出结果依然是1,将char改为int,输出结果就是4

所以,根据上面的示例,可以得出:类对象的成员函数不影响对象所占的内存空间,只有类对象的成员变量会对其所占的内存空间有影响。

2、含有虚函数的类对象的sizeof

class test3
{virtual void t3func() {}
};int main(int argc, char const *argv[])
{   test3 t;cout<<sizeof(t)<<endl;return 0;
}

类对象会因为虚函数的存在增加所占的内存。这是因为:

1.每个含有虚函数的类产生出一堆指向虚函数的指针,放虚表(virtual table vtbl)中。

2.每个含有虚函数的类对象都有一个虚表指针(vptr),指向相关的虚表。虚表指针的设定和重置由每一个类的构造函数、拷贝构造函数、析构函数和operator=自动完成。此外,每一个类所独有的类型信息(用以支持RTTI)也在虚表中的第一个槽中。

所以,多出来的这8字节就是vptr的在x64平台下的sizeof

可以通过以下命令查看虚表

g++ -fdump-class-hierarchy -fsyntax-only c++model.cpp

可以看到,虚表中除了虚函数之外,还有test3的typeinfo

3、内存对齐和补齐

在2的基础上添加一个新的char类型

class test3
{virtual void t3func() {}char a;
};

输出结果如下

因为vptr是8字节,而char类型只有一个字节,所以编译器会进行字节填充,以保证内存对齐,提高运行效率,所以,需要补齐七个字节进行内存对齐,所以输出16

如果不想让编译器进行字节填充,可以使用如下指令

#pragma pack(1)//按照1字节内存对齐
class test3
{virtual void t3func() {}char a;
};
#pragma pack()//取消内存对齐

4、含有static成员的类对象的sizeof

class test3
{virtual void t3func() {}static void sfunc() {}static int a;
};

输出结果依然是8,所以,无论是静态成员函数还是静态成员变量都不增加类对象的大小。因为静态成员永远只存在一份实例,为所有类对象共有。静态成员位于全局数据区

总结:1、静态成员不增加类对象的sizeof。2、普通成员函数也不增加对象的sizeof。3、vtbl是基于类的,虚函数本身不增加对象的sizeof,但是编译器会在类对象内部安插一个vptr,在x64平台下增加8字节内存。如果对象中还有其他成员变量,会额外增加类对象的内存,额外增加的内存主要来自:成员变量本身的大小以及补齐内存的大小

也就是说一个类对象的大小由其非static成员的总和大小、内存填补以及因虚机制产生的额外内存组成

二、static成员

static成员的以下几种调用方式

class test
{
public:static int m_i;
};int test::m_i=-1;int main(int argc, char const *argv[])
{test t;t.m_i=0;test::m_i=1;test *pt=&t;pt->m_i=2;return 0;
}

对应的反汇编代码如下

可见,三种调用方式没有区别,汇编代码都是mov    DWORD PTR [index], value,都等价于test::m_i,因为static成员不在类对象中,因此,存取static成员也不需要使用类对象或者类对象的指针,所以,即使使用类对象或者指针进行调用,最终也会转化成作用域调用。因为static成员函数没有this,所以可以作为回调函数。static成员函数就是个没有this的全局函数

因为static成员变量或者函数并不属于类对象,所以对其取地址,得到的也只是普通的函数指针或者类型的指针,而不是成员变量或者成员函数的指针

三、对象模型

class myobject
{
public:myobject() {}; virtual ~myobject() {}; float getvalue() const{return value;}static int getcount(){return count;}virtual void vfunc() {}protected:float value;static int count;
};

上述代码的对象模型大致如下

如果出现继承,模型还会不一样。上述模型也显示,当调用虚函数时,会通过vptr找到对应的vtbl,然后根据偏移地址对虚函数进行调用。

四、this指针

class A
{
public:int a;A(){printf("A::A() 的 this指针是:%p!\n", this);}void funA() { printf("A::funcA: this = %p\n", this); cout<<&a<<endl;}
};class B
{
public:int b;B(){printf("B::B() 的 this指针是:%p!\n", this);}void funB() { printf("B::funcB: this = %p\n", this); cout<<&b<<endl;}
};class C : public A, public B
{
public:int c;C(){printf("C::C() 的 this指针是:%p!\n", this);}void funC() { printf("C::funcC: this = %p\n", this); cout<<&c<<endl;}void funB() { printf("C::funcB: this = %p\n", this); }
};int main(int argc, char const *argv[])
{   C myc;myc.funA();myc.funB();myc.B::funB();myc.funC();return 0;
}

通过输出以及上述代码可知,类C的内存模型如下

其中,C的this指针与基类列表中的第一个相同(这里是A),其他基类的指针与第一个基类或者派生类的this指针相差成员变量的sizeof(这里A与C的this指针和B的this指针相差sizeof(int a))

参考

《深度探索C++对象模型》

《C++新经典:对象模型》

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

C++对象模型1——类对象的sizeof、static成员、对象模型、this指针相关推荐

  1. C++对象模型5——类对象的内存布局

    一.类对象的内存布局 1.1.单一继承的类对象布局 示例1 class base { public:int m_fai;int m_faj; }; class derive : public base ...

  2. 面向对象(类/对象/封装/继承/static/内存类加载)

    >面向对象:万物皆对象: >类和对象: 从代码的角度来说:类是代码的载体. 从逻辑角度来说:类是静态文件:对象是内存中的地址: 形象的来说,类就是一个模具,是用来生产对象的:对象是基于类产 ...

  3. C++类模板中的static成员

    从类模板实例化的每一个模板类有自己的类模板数据成员,该模板的所有对象共享一个static数据成员. 代码如下: #include <iostream> using namespace st ...

  4. const成员函数、const类对象、mutable数据成员

    1. const成员函数 只是告诉编译器,表明不修改类对象. 但是并不能阻止程序员可能做到的所有修改动作,比如对指针的修改,编译器可能无法检测到 2. 类体外定义的const成员函数,在定义和声明处都 ...

  5. 账户Account类文件编写(static成员使用)

    static类成员是该类所有成员共享一份的数据,一处修改了,全部变更: static成员函数只能调用static成员数据: static const整形int,char,可以在类内声明和初始化,类外不 ...

  6. java类对象的内部结构图解(java对象模型精讲)

    目录: java虚拟机汇总 class文件结构分析 1).class文件常量池中的常量项结构 2). 常用的属性表的集合 类加载过程 1).类加载器的原理以及实现 虚拟机结构分析 1).jdk1.7和 ...

  7. 为什么static成员的类型可以是类本身?又为什么非static成员被限定声明为其自身类对象的指针或引用?...

    看到<C++ Primer>中的一句话,才想起分析一下这个问题:"static 数据成员的类型可以是该成员所属的类类型.非 static 成员被限定声明为其自身类对象的指针或引用 ...

  8. C++对象模型7——类的成员函数、反汇编虚析构函数、RTTI、多态的开销

    一.类成员函数 class test { public:void myfunc(){}virtual void vfunc() {}static void sfunc() {} };void myfu ...

  9. C++对象模型探索--02对象

    对象结构的发展和演化 类对象所占用的空间 类的成员函数不占用类的内存空间 一个类对象至少占用1个字节的内存空间 成员变量占用对象的内存空间 总结:成员变量是包含在每个对象中的,是占用对象字节的.而成员 ...

最新文章

  1. Go对Python产生的冲击
  2. 关于debug.keystore文件用法以及错误处理
  3. Grid SearchCV(网格搜索)与RandomizedSearchCV (随机搜索) 贴近实践的
  4. shell 执行 oracle sql
  5. 数学之路(3)-机器学习(3)-机器学习算法-神经网络[17]
  6. 阿里云大学python_阿里云大学「学习路线」,一站式从入门到高手——Python、Java、前端、运维、数据库、云原生……...
  7. matlab2020数值计算,MATLAB2020从入门到精通
  8. Linux configure 参数解释
  9. Java网络爬虫实操(6)
  10. 004-Python内置数据结构-七种数据结构一览
  11. signature=32c56289e10e63e51063305adfc34ef0,Deconfinement transition and Black Holes
  12. android camera textureview,Android SDK – camera2 – 在TextureView上绘制矩...
  13. dnf红眼补丁在哪下载_dnf狂战士技能血色补丁-DNF狂战士技能红色补丁下载 v3.23完全版--pc6下载...
  14. selenium2 介绍+简单实战
  15. 三维空间数据建模——Smart3D的安装
  16. Google翻译Chrome插件
  17. python使用pip安装openxml_Word文件的OpenXML解析(以Python3为例)
  18. scratch少儿编程航天主题:认识太阳系-八大行星连连看
  19. 生成自定义文字的二维码
  20. 计算机二级能加几个创新创业学分,创新创业活动学分认定细则

热门文章

  1. Tsung压力测试介绍
  2. Electron 实战桌面计算器应用
  3. code第一部分数组:第二十二题 偶数次中查找单独出现一次的数
  4. 如何找出数组中第二大的数
  5. Kafka: Connect
  6. ios第三方库和工具类
  7. apache忽略文件后缀
  8. 用户控件(显示用户信息,修改用户名密码)的WebPart预览版
  9. Eclipse利用Maven的插件部署web项目到远程tomcat服务器
  10. Typora入门(1)