一个类的实例化对象所占空间的大小(对象大小= vptr(可能不止一个) + 所有非静态数据成员大小 + Aligin字节大小(依赖于不同的编译器))
注意不要说类的大小,是类的对象的大小.
首先,类的大小是什么?确切的说,类只是一个类型定义,它是没有大小可言的。
用sizeof运算符对一个类型名操作,得到的是具有该类型实体的大小。
如果
Class A;
A obj;
那么sizeof(A)==sizeof(obj)
那么sizeof(A)的大小和成员的大小总和是什么关系呢,很简单,一个对象的大小大于等于所有非静态成员大小的总和。
为什么是大于等于而不是正好相等呢?超出的部分主要有以下两方面:
1) C++对象模型本身
对于具有虚函数的类型来说,需要有一个方法为它的实体提供类型信息(RTTI)和虚函数入口,常见的方法是建立一个虚函数入口表,这个表可为相同类型的对象共享,因此对象中需要有一个指向虚函数表的指针,此外,为了支持RTTI,许多编译器都把该类型信息放在虚函数表中。但是,是否必须采用这种实现方法,C++标准没有规定,但是这几户是主流编译器均采用的一种方案。
2) 编译器优化
因为对于大多数CPU来说,CPU字长的整数倍操作起来更快,因此对于这些成员加起来如果不够这个整数倍,有可能编译器会插入多余的内容凑足这个整数倍,此外,有时候相邻的成员之间也有可能因为这个目的被插入空白,这个叫做“补齐”(padding)。所以,C++标准紧紧规定成员的排列按照类定义的顺序,但是不要求在存储器中是紧密排列的。
基于上述两点,可以说用sizeof对类名操作,得到的结果是该类的对象在存储器中所占据的字节大小,由于静态成员变量不在对象中存储,因此这个结果等于各非静态数据成员(不包括成员函数)的总和加上编译器额外增加的字节。后者依赖于不同的编译器实现,C++标准对此不做任何保证。
C++标准规定类的大小不为0,空类的大小为1,当类不包含虚函数和非静态数据成员时,其对象大小也为1。
如果在类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针指向虚函数表VTable,在32位机器上,一个对象会增加4个字节来存储此指针,它是实现面向对象中多态的关键。而虚函数本身和其他成员函数一样,是不占用对象的空间的。
我们来看下面一个例子:(此例子在Visual C++编译器中编译运行)
#include <iostream> using namespace std; class A { }; class B { char ch; void func() { } }; class C { char ch1; //占用1字节 char ch2; //占用1字节 virtual void func() { } }; class D { int in; virtual void func() { } }; void main() { A a; B b; C c; D d; cout<< sizeof (a)<<endl; //result=1 cout<< sizeof (b)<<endl; //result=1 //对象c扩充为2个字,但是对象b为什么没扩充为1个字呢?大家帮忙解决 cout<< sizeof (c)<<endl; //result=8 //对象c实际上只有6字节有用数据,但是按照上面第二点编译器优化,编译器将此扩展为两个字,即8字节 cout<< sizeof (d)<<endl; //result=8 } |
综上所述:
一个类中,虚函数、成员函数(包括静态与非静态)和静态数据成员都是不占用类对象的存储空间的。
对象大小= vptr(可能不止一个) + 所有非静态数据成员大小 + Aligin字节大小(依赖于不同的编译器)
#include <iostream> using namespace std; class demo1{ }; class demo2{ static int num; }; class demo3{ virtual int print(){} virtual int print1(){} }; class demo4{ void print(){} static void print1(){} }; class demo5{ char a; }; int _tmain( int argc, _TCHAR* argv[]) { cout<< "空类的大小为:" << sizeof (demo1)<<endl; //当类不包含虚函数和非静态数据成员时,其对象大小也为1。 cout<< "当类不包含虚函数和非静态数据成员时,其对象大小也为:" << sizeof (demo2)<<endl; cout<< "与类中虚函数的个数无关" << sizeof (demo3)<<endl; //大小是4,与类中虚函数的个数无关, cout<< "成员函数(静态和非静态)也不占用类对象的存储空间" << sizeof (demo4)<<endl; cout<< sizeof (demo5)<<endl; demo5 d; cout<< sizeof (d)<<endl; return 0; } |
http://www.cnblogs.com/rollenholt/archive/2012/03/28/2421871.html
一个类的实例化对象所占空间的大小(对象大小= vptr(可能不止一个) + 所有非静态数据成员大小 + Aligin字节大小(依赖于不同的编译器))的更多相关文章
- C++类中的常数据成员和静态数据成员的区别
刚开始学习C++的类和对象的部分,对类中的常数据成员和静态数据成员的概念和用法经常混淆,所以今天整理一下,顺便说一下,今天是我的生日,祝我生日快乐,呵呵. 常数据成员 常数据成员是指在类中定义的不能修 ...
- python中如何统计一个类的实例化对象
类中的静态变量 需要通过类名.静态变量名 来修改 :通过对象不能修改 python中如何统计一个类的实例化对象?? class Person: #静态变量count,用于记录类被实例化的次数 coun ...
- C++学习5-面向对象编程基础(构造函数、转换构造、静态数据成员、静态成员函数、友元)
知识点学习 类 const作用 C语言的const限定符的含义为"一个不能改变值的变量",C++的const限定符的含义为"一个有类型描述的常量": const ...
- C++类静态数据成员与类静态成员函数
from:://http://blog.csdn.net/taina2008/article/details/1684834 把类中的函数都定义成静态函数,这样相当于在编译时就分配了空间,这样不需要实 ...
- 《挑战30天C++入门极限》C++类静态数据成员与类静态成员函数
C++类静态数据成员与类静态成员函数 在没有讲述本章内容之前如果我们想要在一个范围内共享某一个数据,那么我们会设立全局对象,但面向对象的程序是由对象构成的,我们如何才能在类范围内共享数据呢? ...
- C++如何阻止一个类被实例化
(1)定义一个无用的抽象函数,使得类成为抽象类 (2)将构造函数定义为private. 为什么要这样做? 一些工具类,没有被实例化的必要.
- c++语言中类中的静态数据成员为什么必须在类体外初始化?
静态成员属于全局变量,是所有实例化以后的对象所共享的,而成员的初始化你可以想象成向系统申请内存存储数据的过程,显然这种共有对象必须提前申请好,而不是由某个实例化的对象来操纵的. #include &l ...
- Cocos2d-x 3.1.1 学习日志3--C++ 初始化类的常量数据成员、静态数据成员、常量静态数据成员
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u011292087/article/details/37598919 有关const成员.stati ...
- C++类中静态数据成员MAP如何初始化
conv_xxx.hpp class convolution { ... ... typedef std::map<int, std::string> ConvDtMap; static ...
随机推荐
- api的管理工具
一.常用的api管理工具和测试的方法 1.postman 2.Yapi 3.swagger 4.Rap(阿里)
- 44个 Javascript 变态题解析——分分钟让你怀疑人生
原题来自: http://javascript-puzzlers.herokuapp.com/ 第1题 ["1", "2", "3"].ma ...
- Matlab Tricks(二十八)—— 笛卡尔积的实现
笛卡尔积在数学上是一种二元关系,笛卡尔积作用的双方是两个集合,作用的结果是一个新的集合. A×B={(a,b)|a∈Aandb∈B} 现有两向量: >> p = [1, 5, 10]; & ...
- Linux下编译,要下载tar.xz,而不要下载zip,因为换行的编码不一样,对.h.cpp没有影响,但是对脚本有影响 good
原因是 在win下编辑的时候,换行结尾是\n\r , 而在linux下 是\n,所以才会有 多出来的\r但是这个我是直接下载的官网文件解压的,没有动过啊. 破案了. linux下编译要下 .tar.x ...
- 1.通过模板创建MAP版本项目
1.选择mpa+ef+module-zero 取名字 2.用vs打开项目后,在解决方案上右键 还原nuget包 3.打开程序包管理器控制台,选择以EntityFramework结尾的项目,并执行upd ...
- QPointer,QSharedPointer,QWeakPointer的区别与使用例子(QSharedPointer类似Delphi里的引用计数,是强引用,而QWeakPointer是弱引用,不影响原始对象的引用计数,相当于是在暗中观察对象,但保持联系,需要的时候就会出现)
QPointer is a template class that provides guarded pointers to Qt objects and behaves like a normal ...
- mingw-w64-3.10-osx10.9.sh,uninstall-macports.sh,Build NSIS on OSX
https://gist.github.com/artynet/188bb34cfc94acdb554d283a3502770a --cross-compile-prefix=i686-w64-min ...
- WPF与缓动(一) N次缓动
原文:WPF与缓动(一) N次缓动 WPF与缓动(一) N次缓动 ...
- Altera公司高速PCB布线指南
来至Altera公司的高速PCB布线指南,该文档言简意赅,深入浅出,对于日常高速PCB布局布线中经常碰到的一些问题进行了解析.例如:板材的选择,介电常数及损耗因子对高速高频线路的影响,传输线,阻抗控制 ...
- springboot使用logback日志,部署到tomcat不生效问题解决
1.springboot 配置日志方法 使用该方法配置日志,在本地调试可以正常写入日志文件,但是打包发布到tomcat以后日志配置不生效. 2.修改配置 Spring Boot官方推荐优先使用带有-s ...