第一:空类的大小

class CBase
{
};
运行cout<<"sizeof(CBase)="<<sizeof(CBase)<<endl;

输出

sizeof(CBase)=1;

为什么空的什么都没有是1呢?

先了解一个概念:类的实例化,所谓类的实例化就是在内存中分配一块地址,每个实例在内存中都有独一无二的地址。同样空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof为1。

第二:一般非空类大小

class CBase
{
int a;
char *p;
};

运行结果:

sizeof(CBase)=8

第三:有虚函数类

class CBase
{
public:
CBase(void);
virtual ~CBase(void);
private:
int a;
char *p;
};

运行结果:

sizeof(CBase)=12

“C++ 类中有虚函数的时候有一个指向虚函数的指针(vptr),在32位系统分配指针大小为4字节”。

第四:有虚函数类的继承

基类就是上面的了不写了

class CChild :
public CBase
{
public:
CChild(void);
~CChild(void);
private:
int b;
};

运行结果:

sizeof(CChild)=16;

可见子类的大小是本身成员变量的大小加上父类的大小。

另外:

1. 空类
class A
{
}; void main()
{
printf("sizeof(A): %d\n", sizeof(A));
getchar();
}

得到结果为:1。

类的实例化就是给每个实例在内存中分配一块地址。空类被实例化时,会由编译器隐含的添加一个字节。所以空类的size为1。

2.虚函数
class A
{
virtual void FuncA();
virtual void FuncB();
};

得到结果:4

当C++ 类中有虚函数的时候,会有一个指向虚函数表的指针(vptr),在32位系统分配指针大小为4字节。所以size为4.

3.静态数据成员
class A
{
int a;
static int b;
virtual void FuncA();
};

得到结果:8

静态数据成员被编译器放在程序的一个global data members中,它是类的一个数据成员.但是它不影响类的大小,不管这个类实际产生了多少实例,还是派生了多少新的类,静态成员数据在类中永远只有一个实体存在。

而类的非静态数据成员只有被实例化的时候,他们才存在.但是类的静态数据成员一旦被声明,无论类是否被实例化,它都已存在.可以这么说,类的静态数据成员是一种特殊的全局变量.

所以该类的size为:int a型4字节加上虚函数表指针4字节,等于8字节。

4.普通成员函数
class A
{
void FuncA();
}

结果:1

类的大小与它的构造函数、析构函数和其他成员函数无关,只已它的数据成员有关。

5.普通继承
class A
{
int a;
};
class B
{
int b;
};
class C : public A, public B
{
int c;
};

结果为:sizeof(C) =12.

可见普通的继承,就是基类的大小,加上派生类自身成员的大小。

6.虚拟继承
class C : virtual public A, virtual public B
{
int c;
};

结果:16.

当存在虚拟继承时,派生类中会有一个指向虚基类表的指针。所以其大小应为普通继承的大小(12字节),再加上虚基类表的指针大小(4个字节),共16字节。

类的大小问题实验剖析:

1、空类:

C++编译器强制给这种类插入一个缺省成员,长度为1。如果有自定义的变量,变量将取代这个缺省成员。

class A

{};

cout<<sizeof(A); //输出1
2、只有一个char型
class A

{

char c;

};

cout<<sizeof(A); //输出1
3、有5个char型
class A

{

char a,b,c,d,e;

};

cout<<sizeof(A); //输出5
4、一个char型 + 一个int型:字节对齐
class A
{
char c; int a; }; cout<<sizeof(A); //输出8
5、2个char型 + 一个int型
class A

{

char c,d;

int a;

};

cout<<sizeof(A); //输出8
6、5个char型 + 一个int型
class A

{

char c,d,e,f,g;

int a;

};

cout<<sizeof(A); //输出12
7、1个char型 + 1个int型 + 2个char型
class A
{
char c;
int a;
char d,e; }; cout<<sizeof(A); //输出12
8、普通函数不占空间
class A
{
void B(){ int d; }//0Byte
int C(){}; }; cout<<sizeof(A); //输出1,等同于空类
9、虚函数 占4个字节:指向虚函数表的指针
class A
{
virtual void C(){}
}; cout<<sizeof(A); //输出4
10、多个虚函数等同于1个虚函数
class A
{
virtual void C(){} virtual void D(){}
}; cout<<sizeof(A); //输出4
11、多继承问题中sizeof
class b{};

class c :public b

{

virtual void fun() = 0;
}; class d :public b ,public c{}; cout<<sizeof(d); //输出8,字节对齐(b+c)
12、单继承问题中sizeof
class b{};

class c :public b

{

virtual void fun() = 0;

};

class d :public c{};

cout<<sizeof(c); //输出4

cout<<sizeof(d); //输出4
13、静态数据成员 和 成员函数 不占空间
class A

{

static int a;

static int b(){};

};

cout<<sizeof(A); //输出1
14、const数据变量占空间 和 const成员函数不占空间
class A

{

public:

const int b;

const int c;

virtual void f(){}

int d() const{}

int e() const{}

virtual void g(){}

A() :b(2), c(3)

{

}

};

cout<<sizeof(A); //输出12= 4+4+4(多个虚函数算一个)

空类的大小

class Base
{
public:
Base();
~Base(); };
  • 注意到我这里显示声明了构造跟析构,但是sizeof(Base)的结果是1.

  • 因为一个空类也要实例化,所谓类的实例化就是在内存中分配一块地址,每个实例在内存中都有独一无二的地址。同样空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof为1。

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

接着看下面一段代码

class Base
{
public:
Base();
virtual ~Base(); //每个实例都有虚函数表
void set_num(int num) //普通成员函数,为各实例公有,不归入sizeof统计
{
a=num;
}
private:
int a; //占4字节
char *p; //4字节指针
}; class Derive:public Base
{
public:
Derive():Base(){};
~Derive(){};
private:
static int st; //非实例独占
int d; //占4字节
char *p; //4字节指针 }; int main()
{
cout<<sizeof(Base)<<endl;
cout<<sizeof(Derive)<<endl;
return 0;
}

结果自然是

12

20
  • Base类里的int  a;char *p;占8个字节。

  • 而虚析构函数virtual ~Base();的指针占4子字节。

  • -其他成员函数不归入sizeof统计。

  • Derive类首先要具有Base类的部分,也就是占12字节。

  • int  d;char *p;占8字节

  • static int st;不归入sizeof统计

  • 所以一共是20字节。

在考虑在Derive里加一个成员char c;

class Derive:public Base
{
public:
Derive():Base(){};
~Derive(){};
private:
static int st;
int d;
char *p;
char c; };

这个时候,结果就变成了

12

24

一个char c;增加了4字节,说明类的大小也遵守类似class字节对齐,的补齐规则。

至此,我们可以归纳以下几个原则:

1.类的大小为类的非静态成员数据的类型大小之和,也就是说静态成员数据不作考虑。

2.普通成员函数与sizeof无关。

3.虚函数由于要维护在虚函数表,所以要占据一个指针大小,也就是4字节。

4.类的总大小也遵守类似class字节对齐的,调整规则。

5、不占空间的有:普通函数,静态数据成员,静态成员函数。

6、无论多少个,只相当于一个所占的空间:虚函数。

7、空类占1个字节。

8、既有字符型又有整型,要考虑字节对齐。

9、普通数据成员、const数据成员占空间;静态成员不占空间。

参考:

https://blog.csdn.net/u010069101/article/details/51045840

https://blog.csdn.net/hairetz/article/details/4171769

https://blog.csdn.net/zzhongcy/article/details/38361755

C++类的大小——sizeof(class)的更多相关文章

  1. 类的大小——sizeof 的研究

    类的大小——sizeof 的研究(1) 先看一个空的类占多少空间? class Base { public: Base(); ~Base(); }; 注意到我这里显示声明了构造跟析构,但是sizeof ...

  2. sizeof求类的大小

    用sizeof求类的大小,http://blog.csdn.net/szchtx/article/details/10254007(sizeof浅析(三)——求类的大小),这篇博文给出了非常详尽的举例 ...

  3. c++空类的大小

    初学者在学习面向对象的程序设计语言时,或多或少的都些疑问,我们写的代码与最终生编译成的代码却大相径庭,我们并不知道编译器在后台做了什么工作.这些都是由于我们仅停留在语言层的原因,所谓语言层就是教会我们 ...

  4. C++空类以及没有成员变量的类的大小

    关于C++中空类的大小为1,我们大家都有所了解,但是除了空类之外的其他一些没有成员变量的类的大小,还是有很多不明之处的. 我们来看如下一个例子: #include<iostream> us ...

  5. C++类的大小

    C++类的大小   一个空类class A{};的大小为什么是1,因为如果不是1,当定义这个类的对象数组时候A objects[5]; objects[0]和objects[1]就在同一个地址处,就无 ...

  6. 关于虚拟继承类的大小问题探索,VC++ 和 G++ 结果是有区别的

    昨天笔试遇到个 关于类占用的空间大小的问题,以前没怎么重视,回来做个试验,还真发现了问题,以后各位笔试考官门,出题时请注明是用什么编译器. vc6/vc8 cl 和 Dev-C 的g++ 来做的测试: ...

  7. C++类对象大小的计算

    (一)常规类大小计算 C++类对象计算需要考虑很多东西,如成员变量大小,内存对齐,是否有虚函数,是否有虚继承等.接下来,我将对此举例说明. 以下内存测试环境为Win7+VS2012,操作系统为32位 ...

  8. C++类的大小计算汇总

    C++中类涉及到虚函数成员.静态成员.虚继承.多继承.空类等. 类,作为一种类型定义,是没有大小可言的. 类的大小,指的是类的对象所占的大小.因此,用sizeof对一个类型名操作,得到的是具有该类型实 ...

  9. C++学习笔记(8)----C++类的大小

    C++类的大小 (i) 如下代码: #include<iostream> using namespace std; class CBase { }; class CDerive :publ ...

随机推荐

  1. Linux服务器---流量监控ntop

    Ntop Ntop 是一款类似于sniffer的流量监控工具,它显示出的流量信息比mrtg更加详细. 1 .安装一些依赖软件 [root@localhost bandwidthd]#  yum ins ...

  2. java == 与 equals 相同与不同点

    java中与很多有意思又值得深究的点. 写这篇文章呢,是由于在百度知道中看到一个问题:怎样比较两个对象是否相同.这又使我想到了另外一个问题,== 和 equals有什么不同?写了几行代码,看了几篇文章 ...

  3. 75.Java异常处理机制-自定义异常

    package testDate; //自定义异常 public class MyException extends Exception{ public MyException(){ } public ...

  4. Django后端项目---- Rest Framework(2)

    一.认证(补充的一个点) 认证请求头 #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import API ...

  5. 使用Holer将本地端口映射到公网

    What is holer Holerexposes local servers behind NATs and firewalls to the public internet over secur ...

  6. Solr创建核的方法

    Solr创建核的方法,简单粗暴 就是进入到solrhome中进行复制粘贴这个collection2 然后进入到conf中,修改一下name 然后从新启动tomcat

  7. 在nginx的http模块下面,一个server就可以看做一个站点,配置形式大概是这样的:

    http { index index.php index.htm index.html; server { server_name www.site1.com; location / { # [... ...

  8. Linux学习笔记之yum安装和卸载软件

    # yum -y install 包名(支持*) :自动选择y,全自动 # yum install 包名(支持*) :手动选择y or n # yum remove 包名(不支持*) # rpm -i ...

  9. mysql判断两个时间段是否有交集

    //判断两个时间段是否有交集 private function checkTimeCross($start_time,$end_time){ $sql ) AND ((start_time > ...

  10. MySQL乐观锁和悲观锁的概念和原理

    乐观锁:在取数据时不加锁,等处理完逻辑的时候,查看是否与上一次相同,若相同则更新,若不同则拒绝. 悲观锁:在取数据时就加上锁,只有更新完数据之后,别的用户才可以进行读. (个人总结)