zoukankan      html  css  js  c++  java
  • C++类的大小——sizeof(class)

    第一:空类的大小

    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
    ", 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

  • 相关阅读:
    ##日常代码中,我们需要配的几种数据源的配置文件
    ##Sping框架IOC中常用的注解大家一定要记住
    ##事务管理器工具类
    ##管理连接的工具类 用来实现连接 和线程的绑定
    ##处理转账事务的多线程问题,让其在一个线程处理账务的增加和减少
    学习笔记——spark安装配置
    学习笔记——spark基础实验二
    学习笔记——spark实验一
    课堂测试之数据清洗
    Mapreduce实例——WordCount
  • 原文地址:https://www.cnblogs.com/ZY-Dream/p/10016731.html
Copyright © 2011-2022 走看看