类的大小是什么?确切的说,类只是一个类型定义,它是没有大小可言的。 用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(类)的更多相关文章

  1. sizeof(类名字)

    析构函数,跟构造函数这些成员函数,是跟sizeof无关的,因为我们的sizeof是针对实例,而普通成员函数,是针对类体的,一个类的成员函数,多个实例也共用相同的函数指针,所以自然不能归为实例的大小. ...

  2. 全面总结sizeof的用法(定义、语法、指针变量、数组、结构体、类、联合体、位域位段)

    一.前言 编译环境是vs2010(32位). <span style="font-size:18px;">#include<iostream> #inclu ...

  3. sizeof与类,继承,virtual的种种

    对虚继承层次的对象的内存布局,在不同编译器实现有所区别. 首先,说说GCC的编译器. 它实现比较简单,不管是否虚继承,GCC都是将虚表指针在整个继承关系中共享的,不共享的是指向虚基类的指针. clas ...

  4. sizeof与类,继承,virtual的种种(整理)

    对虚继承层次的对象的内存布局,在不同编译器实现有所区别. 首先,说说GCC的编译器. 它实现比较简单,不管是否虚继承,GCC都是将虚表指针在整个继承关系中共享的,不共享的是指向虚基类的指针. clas ...

  5. class类的sizeof计算

    class no_virtual { public: void fun1() const{} int fun2() const { return a; } private: int a; } clas ...

  6. 【c++内存分布系列】单独一个类

    首先要明确类型本身是没有具体地址的,它是为了给编译器生成相应对象提供依据.只有编译器生成的对象才有明确的地址. 一.空类 形如下面的类A,类里没有任何成员变量,类的sizeof值为1. #includ ...

  7. Java类的继承与多态特性-入门笔记

    相信对于继承和多态的概念性我就不在怎么解释啦!不管你是.Net还是Java面向对象编程都是比不缺少一堂课~~Net如此Java亦也有同样的思想成分包含其中. 继承,多态,封装是Java面向对象的3大特 ...

  8. C/C++面试题集锦(一)

    C/C++面试题集锦(一) */--> C/C++面试题集锦(一) 在类的头文件中进行声明然后在定义文件中实现有什么意义? 一方面使类的实现只编译一次,提高编译效率:另一方面可以实现类的接口和实 ...

  9. C++ 继承之虚继承与普通继承的内存分布

    仅供互相学习,请勿喷,有观点欢迎指出~ class A { virtual void aa(){}; }; class B : public virtual A { ]; //加入一个变量是为了看清楚 ...

随机推荐

  1. 如何给apk文件签名

    1.签名的意义 为了保证每个应用程序开发商合法ID,防止部分开放商可能通过使用相同的Package Name来混淆替换已经安装的程序,我们需要对我们发布的APK文件进行唯一签名,保证我们每次发布的版本 ...

  2. Moq/moq4

    moq The most popular and friendly mocking framework for .NET var mock = new Mock<ILoveThisFramewo ...

  3. iPhoneX页面安全区域与内容重叠问题

    转载自:https://www.cnblogs.com/lolDragon/p/7795174.html 1.  iPhoneX的介绍 屏幕尺寸 我们熟知的iPhone系列开发尺寸概要如下: △ iP ...

  4. CCF-20170901

    试题编号:    201709-1 试题名称:    打酱油 时间限制:    1.0s 内存限制:    256.0MB 问题描述 小明带着N元钱去买酱油.酱油10块钱一瓶,商家进行促销,每买3瓶送 ...

  5. B树和TreeSet与TreeMap

    1. 此前二叉搜索树相关的内容我们均假设可以把整个数据结构存储在计算机的内存中,但是如果数据量过大时,必须把数据结构放在磁盘上,导致大O模型不在适用.目前计算机处理器每秒至少可以执行5亿条指令,磁盘访 ...

  6. spring中使用@Async注解进行异步处理

    引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3. ...

  7. 2015/9/1 Python基础(6):列表

    列表和字符串类型很相似,是同样的序列式数据类型.但是字符串只能由字符组成,列表可以保留任意数目的Python对象的灵活的容器.Python的列表比C的数组要灵活,数组里面只能是一种类型,列表可以有多种 ...

  8. Hibernate数据连接不能正常释放的原因,以及在监听中获取apolicationContext上下文

    Hibernate数据库连接不能正常释放: https://blog.csdn.net/u011644423/article/details/44267301 监听中获取applicationCont ...

  9. Unity下的ECS框架 Entitas简介

    最近随着守望先锋制作组在gdc上发布的一个关于ecs的talk,ecs这个架构算是得到了一定的曝光度. 在这之前,github上就一直有一个C#的ecs框架名为Entitas,截止现在已经有1300+ ...

  10. Apache2.4+Tomcat7 集群

    Apache2.4+Tomcat7 集群: 1.下载并安装相对应的软件 apache下载地址:http://httpd.apache.org/ 这里使用apache2.4 tomcat下载地址:htt ...