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 { ]; //加入一个变量是为了看清楚 ...
随机推荐
- Spring源码解析-autowiring自动装配的实现
IoC容器提供了自动依赖装配的方式,为应用IoC容器提供很大的方便.在自动配置中,不需要显式的去指定Bean属性,只需要配置autowiring属性,IoC容器会根据这个属性配置,使用反射的方式查找属 ...
- GYM 101875 2018 USP-ICMC
3月自训 (1):10/12 A: 题意:每个人可以连边,最远连到第(i+k)%n个人,边权为这个人与另一个人连边距离,求生成一颗最大生成树的权值和是多少 题解:可以证明的是,我们每一个人都向接下来的 ...
- tp if condition in_array用法
<if condition="in_array($vo['status'],[3])"> <a href="javascript:void(0);&qu ...
- [LeetCode] 6. ZigZag Conversion ☆☆☆
The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like ...
- mysql 中 group_concat()用法
基本语法:group_concat([DISTINCT] 要连接的字段 [Order BY 排序字段 ASC/DESC] [Separator '分隔符']) 初始数据: ...
- Xamarin入门浅析
1. 安装 1) 使用标准安装流程(JDK1.6 -> Android SDK -> NDK -> Xamarin Studio -> Xamarin Visual Studi ...
- [cerc2012][Gym100624D]20181013
题意:一个序列,如果存在一个连续子序列,满足该子序列中没有只存在一次的序列,则原序列为boring,否则non-boring 题解: 分治递归 对一个序列,如果找到了一个只出现一次的数位于a[x],则 ...
- 多重部分和问题 (dp)
题目描述 有n种不同大小的数字Ai,每种各Mi个.判断是否能从这些数字中选出若干个使它们的和恰好为K. 这个问题可以用DP求解,递推关系式的定义会影响最终的复杂度. 第一种定义: dp[i+1][j] ...
- input placeholder 兼容问题
placeholder是html5出的新特性,ie9以下是不兼容的, 那么为了兼容ie9 我们需要对他做处理 //jq的处理方式$(function(){ jQuery('[placeholder] ...
- 今天安装了arch,感觉不错,这速度可以
虽然没有想想中的那么那么快,不过已经可以了 总结一下遇到的问题以及i自己安装的软件 1.u盘硬盘不能自动挂载 安装gvfs 2.不能读写挂载 安装ntfs-3g 3.时间不对 照wiki上的说 #ln ...