sizeof(类)
类的大小是什么?确切的说,类只是一个类型定义,它是没有大小可言的。 用sizeof运算符对一个类型名操作,得到的是具有该类型实体的大小。首先:我们要知道什么是类的实例化,所谓类的实例化就是在内存中分配一块地址
用sizeof对类名操作,得到的结果是该类的对象在存储器中所占据的字节大小,由于静态成员变量不在对象中存储,因此这个结果等于各非静态数据成员(不包括成员函数)的总和加上编译器额外增加的字节。后者依赖于不同的编译器实现,C++标准对此不做任何保证。
确定类大小的几个原则:
- 为类的非静态成员数据的类型大小之和
- 有编译器额外加入的成员变量的大小,用来支持语言的某些特性(如:指向虚函数的指针)
- 为了优化存取效率,进行的边缘调整
- 与类中的构造函数,析构函数以及其他的成员函数无关
下面分情况讨论:
编译器:vs2013
1. 空类
#include <iostream>
using namespace std; class A{}; int main()
{
cout << sizeof(A) << endl;
system("pause");
}
输出:1
C++标准规定类的大小不为0,空类的大小为1,当类不包含虚函数和非静态数据成员时,其对象大小也为1。这就是我们刚才所说的实例化的原因(空类同样可以被实例化),每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址
2. 简单类
使用sizeof求这种简单类,结果和求结构体的sizeof是一样的,需要考虑偏移和对齐。要注意的是static变量不属于类的一部分,如果类中定义了static变量,求sizeof时可以忽略它们。
#include <iostream>
using namespace std; class A
{
int a;
};
class B
{
char a;
};
class C
{
int a;
char b;
}; int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;
system("pause");
}
输出:
4 sizeof(int)
1 sizeof(char)
8 sizeof(int) + sizeof(char)(考虑对齐)
3. 带虚函数的类
虚函数放在虚表中,类中定义了虚函数,需要存放一个指向虚表的指针
如果在类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针指向虚函数表VTable,在32位机器上,一个对象会增加4个字节来存储此指针,它是实现面向对象中多态的关键。而虚函数本身和其他成员函数一样,是不占用对象的空间的
#include <iostream>
using namespace std; class A
{
int a;
virtual void fun(){}
virtual void fun1(){}
virtual void fun3(){}
}; int main()
{
cout << sizeof(A) << endl;
system("pause");
}
输出
8 sizeof(int) + sizeof(虚表指针)
4. 普通继承(父类不含虚函数)
#include <iostream>
using namespace std; class A
{
int num;
char str;
};
class B : public A
{
char str2;
int num2;
}; int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
system("pause");
}
输出:
8 sizeof(类A)
16 sizeof(类A) + sizeo(类B)
一般来说,普通继承的空间计算结果应当是sizeof(基类)+sizeof(派生类),然后考虑对齐,内存空间必须是类中数据成员所占用最大空间的整数倍。不过这是一般情况,具体怎么算要看编译器,codeblocks把类B看成12,因为把str2和str放在一起了
5.普通继承(父类含虚函数)
#include <iostream>
using namespace std; class A
{
int num;
virtual void fun(){}
};
class B : public A
{
int num2;
}; int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
system("pause");
}
输出:
8 sizeof(类A)
12 sizeof(类A) + sizeo(类B)
6. 普通继承(含虚函数的子类普通继承含虚函数的父类)
这个要注意的一点是,虽然子类和父类都包含虚函数, 但它们存放于同一个虚表中,因此只需要一个指针
#include <iostream>
using namespace std; class A
{
int num;
virtual void fun(){}
};
class B : public A
{
int num2;
virtual void fun1(){}
}; int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
system("pause");
}
输出:
8 sizeof(int) + sizeof(指针)
12 sizeof(int) + sizeof(int) + sizeof(指针) (继承后只有一个虚表)
7. 子类虚继承父类
sizeof(子类)=sizeof(基类)+sizeof(虚表指针)+sizeof(子类数据成员) 此外,如果子类和基类都有虚函数,各自用各自的虚表
#include <iostream>
using namespace std; class A
{
int num;
};
class B : virtual public A
{
int num2;
}; int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
system("pause");
}
输出:
4
12 sizeof(A) + sizeof(B) + sizeof(虚继承指针)
#include <iostream>
using namespace std; class A
{
int num;
virtual void fun(){}
};
class B : virtual public A
{
int num2;
virtual void fun1(){}
}; int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
system("pause");
}
输出:
8
20 sizeof(A) + sizeof(B) + sizeof(虚继承指针) + sizeof(A类虚表指针) + sizeof(B类虚表虚指针)
8. 多重虚继承
虚继承存在的意义就是为了减少内存开销和二义性,实现对象共享。
#include <iostream>
using namespace std; class A
{
int num;
};
class B : virtual public A
{
int num2;
}; class C : virtual public A
{
int num3;
}; class D : public B, public C
{
int num4;
}; int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;
cout << sizeof(D) << endl;
system("pause");
}
输出:
4
12
12
24
D中包含a,b,c,d四个数据成员,还包含两个指向虚基类A的指针,这种情况下,VS和CB都没有将两个指针合为一个。这种情况也可以这样考虑,sizeof(D)=sizeof(B)+sizeof(C),但由于是虚继承,虚基类A中数据成员a只需要保留一份,而我们算了两次,所以还需要减去A的数据成员,所以公式应当是sizeof(D)=sizeof(D的非静态数据成员) + sizeof(B)+sizeof(C)-sizeof(A的非静态数据成员)。
参考资料:http://blog.csdn.net/szchtx/article/details/10254007
sizeof(类)的更多相关文章
- sizeof(类名字)
析构函数,跟构造函数这些成员函数,是跟sizeof无关的,因为我们的sizeof是针对实例,而普通成员函数,是针对类体的,一个类的成员函数,多个实例也共用相同的函数指针,所以自然不能归为实例的大小. ...
- 全面总结sizeof的用法(定义、语法、指针变量、数组、结构体、类、联合体、位域位段)
一.前言 编译环境是vs2010(32位). <span style="font-size:18px;">#include<iostream> #inclu ...
- sizeof与类,继承,virtual的种种
对虚继承层次的对象的内存布局,在不同编译器实现有所区别. 首先,说说GCC的编译器. 它实现比较简单,不管是否虚继承,GCC都是将虚表指针在整个继承关系中共享的,不共享的是指向虚基类的指针. clas ...
- sizeof与类,继承,virtual的种种(整理)
对虚继承层次的对象的内存布局,在不同编译器实现有所区别. 首先,说说GCC的编译器. 它实现比较简单,不管是否虚继承,GCC都是将虚表指针在整个继承关系中共享的,不共享的是指向虚基类的指针. clas ...
- class类的sizeof计算
class no_virtual { public: void fun1() const{} int fun2() const { return a; } private: int a; } clas ...
- 【c++内存分布系列】单独一个类
首先要明确类型本身是没有具体地址的,它是为了给编译器生成相应对象提供依据.只有编译器生成的对象才有明确的地址. 一.空类 形如下面的类A,类里没有任何成员变量,类的sizeof值为1. #includ ...
- Java类的继承与多态特性-入门笔记
相信对于继承和多态的概念性我就不在怎么解释啦!不管你是.Net还是Java面向对象编程都是比不缺少一堂课~~Net如此Java亦也有同样的思想成分包含其中. 继承,多态,封装是Java面向对象的3大特 ...
- C/C++面试题集锦(一)
C/C++面试题集锦(一) */--> C/C++面试题集锦(一) 在类的头文件中进行声明然后在定义文件中实现有什么意义? 一方面使类的实现只编译一次,提高编译效率:另一方面可以实现类的接口和实 ...
- C++ 继承之虚继承与普通继承的内存分布
仅供互相学习,请勿喷,有观点欢迎指出~ class A { virtual void aa(){}; }; class B : public virtual A { ]; //加入一个变量是为了看清楚 ...
随机推荐
- POJ3164:Command Network(有向图的最小生成树)
Command Network Time Limit: 1000MS Memory Limit: 131072K Total Submissions: 20766 Accepted: 5920 ...
- How Many Nines ZOJ - 3950 打表大法好
If we represent a date in the format YYYY-MM-DD (for example, 2017-04-09), do you know how many 9s w ...
- c#知识梳理
转:http://www.cnblogs.com/zhouzhou-aspnet/articles/2591596.html 本文是一个菜鸟所写,本文面向的人群就是像我这样的小菜鸟,工作一年也辛辛苦苦 ...
- 寻找最大连续子序列/Find the max contiguous subsequence
寻找最大连续子序列 给定一个实数序列X1,X2,...Xn(不需要是正数),寻找一个(连续的)子序列Xi,Xi+1,...Xj,使得其数值之和在所有的连续子序列数值之和中为最大. 一般称这个子序列为最 ...
- 安卓弹出键盘隐藏fixed定位相关的元素(obj必须是class)
//安卓弹出键盘隐藏fixed定位相关的元素(obj必须是class) function displayFixed(obj){ var h = document.body.scrollHeight; ...
- [实战篇入门]01-POI读Excel
这一章的内容就是告诉各位同学如何入门POI的简单使用,再之后我们还会学习如何封装模版,由于个人时间问题,不定期更新!如果有需要,请再QQ中联系我,好了,开始工作! 新建一个Java项目,首先需要一些列 ...
- 51Nod 1182 完美字符串
Input示例 dad Output示例 77 #include "bits/stdc++.h" using namespace std; #define LL long long ...
- [Luogu 3224] HNOI2012 永无乡
[Luogu 3224] HNOI2012 永无乡 特别水一个平衡树题. 不认真的代价是调试时间指数增长. 我写的 SBT,因为 Treap 的 rand() 实在写够了. 用并查集维护这些点的关系, ...
- Linux修改服务器ip
Linux基础二(修改ip地址.修改网关.修改DNS服务器.重新启动网络配置) 网络的初始化 .ip地址的修改(临时生效) 使用ifconfig命令 ifconfig 网卡名 ip地址 netma ...
- SourceTree for mac 注册过程(v2.7.6a)
背景 为啥要自己注册呢,往上一堆一堆的老版本许可证偏不用,就愿意定制自己的账号style. 搞了半天,还是觉得pycharm自带的git工具就挺好用了,闲的没事记录一下. 要点 百度搜索的地址可以进入 ...