• 【转】C++类的sizeof大小


    转自https://blog.csdn.net/zhengjihao/article/details/77825269

    其中有的描述与实际GCC上执行的结果不符,不过其中的分析思路需要掌握。

    以下是GCC的实际执行结果:

      1 #include <iostream>
      2 using namespace std;
      3 
      4 int *pointer;
      5 
      6 class NullCls {};
      7 
      8 class NullVirtual {
      9 public:
     10     virtual void fun() {};
     11     virtual void fun2() {};
     12 };
     13 
     14 class CSI {
     15 public:
     16     char b;
     17     short c;
     18     int a;
     19 };
     20 
     21 class CIS {
     22 public:
     23     char b;
     24     int a;
     25     short c;
     26 };
     27 
     28 class CSV {
     29 public:
     30     char b;
     31     short c;
     32     virtual void fun() {};
     33 };
     34 
     35 class CVS {
     36 public:
     37     char a;
     38     virtual void fun() {};
     39     short b;
     40 };
     41 
     42 class StaticInt {
     43 public:
     44     char b;
     45     virtual void fun() {};
     46     static int c;  // 放在程序的global data members中
     47 };
     48 
     49 class Method {
     50 public:
     51     void fun() {};
     52 };
     53 
     54 class Parent {
     55 public:
     56     int c;
     57 };
     58 
     59 class Son : public Parent {
     60 public:
     61     int b;
     62 };
     63 
     64 class Parent2 {
     65 public:
     66     int a;
     67     char b;
     68 };
     69 
     70 class Son2 : public Parent2 {
     71 public:
     72     char c;
     73 };
     74 
     75 class A
     76 {
     77     virtual void fun() {}
     78 };
     79 
     80 class B
     81 {
     82     virtual void fun2() {}
     83 };
     84 
     85 class C : virtual public  A, virtual public B
     86 {
     87 public:
     88     virtual void fun3() {}
     89 };
     90 
     91 class C2 : public A, public B
     92 {
     93 public:
     94     virtual void fun3() {}
     95 };
     96 
     97 void size(string name, int s) {
     98     cout << name << "=" << s << endl;
     99 }
    100 
    101 int main(){
    102     size("pointer", sizeof(pointer));  // 8
    103     size("NullCls", sizeof(NullCls));  // 1
    104     size("NullVirtual", sizeof(NullVirtual));  // 8
    105     size("CSI", sizeof(CSI));  // 8
    106     size("CIS", sizeof(CIS));  // 12
    107     size("CSV", sizeof(CSV));  // 16
    108     size("CVS", sizeof(CVS));  // 16
    109     size("StaticInt", sizeof(StaticInt));  // 16
    110     size("Method", sizeof(Method));  // 1
    111     size("Son", sizeof(Son));  // 8
    112     size("Son2", sizeof(Son2));  // 12
    113     size("C", sizeof(C));  // 16
    114     size("C2", sizeof(C2));  // 16
    115 }

    《原文如下》

    1空类

    1 class A {};

    大小为1。 

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

    class A
    {
      public:
        virtual void fun() {};
        virtual void fun2() {};
    };

    大小为4。 

    当C++类中有虚函数的时候,会有一个指向虚函数表(V-table)的指针,所有的虚函数都在这个表中。指针大小为4,所以size为4。

    在来看如下代码:

    class A
    {
      public:
        char b;
        short c;
        int a;
    };
    class B
    {
      public:
        char a;
        int c;
        short b;
    };

    考虑数据对齐,大小分别为 8 和 12。如果我们将int换成虚函数,会是什么结果呢?

    class A
    {
    public:
      char b;
      short c;
      virtual void fun() {}
    };
    class B
    {
    public:
      char a;
      virtual void fun() {}
      short b;
    };

    大小分别为 8 8。 都是占4个字节,结果不一样。 这是因为,为了效率问题,编译器(gcc 和 微软)一般会把虚指针放在类的内存空间的最前面的位置,不管虚函数声明的位置。考虑对齐,大小都是 4 +1+1+2 = 8.

    3 静态数据成员

    class A
    {
    public:
      char b;
      virtual void fun() {};
      static int c;
    };

    大小为8。 

    静态数据成员被编译器放在程序的一个global data members中,它是类的一个数据成员,但不影响类的大小。不管这个类产生了多少个实例,还是派生了多少新的类,静态数据成员只有一个实例。静态数据成员,一旦被声明,就已经存在。 考虑到数据对齐, 最终是8字节。

    4 普通成员函数

    class A
    {
    public:
      void fun() {};
    };

    大小为1。 

    类的大小与构造函数,析构函数,普通成员函数无关。

    5 普通单继承

    class A 
    {
      int c;
    };
    class B : public A
    {
      int a;
    };

    大小分别为4 和 8。 可以看到普通的继承就是基类的大小+派生类自身的大小。注意数据对齐。 

    注意:类的数据成员按其声明顺序加入内存,无访问权限无关,只看声明顺序。

    class A
    {
      int a;
      char b;
    };
    class C : public A
    {
      public:
      char c;
    };

    上面这段代码,不同的编译器结果不同,VS的结果是 8 和 12, GCC是8 和 8。VS中 相当于

    class C
    {
      A a;
      char c;
    };

    A的大小为8,对齐值为4, 则考虑总体对齐 8 + 1 + 3(padding) = 12。 

    GCC 则是

    class C
    {
      int a;
      char b;
      char c;
    };

    结果为 4 + 1 + 1 + 2 = 8。【与实际执行有出入】

    6 含虚函数的单继承

    class A
    {
      virtual void fun () {}
    };
    class C : public A
    {
    public:
      virtual void fun2() {}
    };

    大小分别为4 和 4。派生类继承了基类的虚指针,所以大小为4。

    7 虚单继承

    class A
    {
      virtual void fun () {}
    };
    
    class C : virtual public A
    {
    public:
      virtual void fun2() {}
    };

    这段代码,VS和gcc结果不一样。VS为 4 和 12。 gcc为4 和4。

    8 普通多继承

    class A
    {
      int a;
      char b;
    };
    
    class B
    {
      char b;
    };
    class C : public A, public B
    {
    public:
      char c;
    };

    VS:8 1 12 

    GCC:8 1 8
    VS中相当于把A B当做整体看待, GCC则拆分整合。

    9 虚函数多继承

    class A
    {
      virtual void fun() {}
    };
    
    class B
    {
      virtual void fun2() {}
    };
    class C : public A, public B
    {
    public:
      virtual void fun3() {}
    };

    结果为 4 4 8。分析:类A一个虚函数表,类B一个虚函数表,类C继承了两个虚函数表,并把自己的虚函数写在了继承顺序中第一个虚函数表中。

    10 虚继承

    class A
    {
      virtual void fun() {}
    };
    
    class B
    {
      virtual void fun2() {}
    };
    class C : virtual public A, virtual public B
    {
    public:
      virtual void fun3() {}
    };

    GCC: 4 4 8   VS:4 4 16

  • 相关阅读:
    04.sys
    leetcode算法-加油站
    Spring动态AOP
    (java反射-JDK动态代理)+CGLIB动态代理
    java反射-基础语法
    leetcode算法-验证回文串
    leetcode算法-盛最多水的容器
    leetcode算法-两数之和
    leetcode算法-三数之和
    leetcode算法-最长和谐子序列
  • 原文地址:https://www.cnblogs.com/qxxnxxFight/p/11134143.html
Copyright © 2020-2023  润新知