• 类对象所占用的内存空间


      一个类的实例化对象所占空间的大小? 注意不要说类的大小,是类的对象的大小。 首先,类的大小是什么?确切的说,类只是一个类型的定义,它是没有大小可言的,用sizeof运算符对一个类型名操作,得到的是具有该类型实体的大小

     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 class A
     6 {
     7 };
     8 
     9 int main()
    10 {
    11     A obj;
    12     int nLen = sizeof(obj);
    13     cout << nLen << endl; //sizeof(一个空类)为什么等于1?
    14 
    15     return 0;
    16 }

    可以看到一个空类对象的大小1.

    一个空类对象的大小是1,为什么不是0?

      初学者肯定会很烦恼?类A明明是空类,它的大小应该为0,为什么编译器输出的结果为1呢?这就是实例化的原因(空类同样被实例化),每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存中得到了独一无二的地址,所以obj的大小是1.

      

    打断点调试的时候,选中obj,然后按快捷键shift+F9

    可以看到obj的地址是0x0019f77b;然后点击vs菜单栏上的窗口----内存-----内存(1)

    然后把obj的内存地址粘贴过来:

     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 class A
     6 {
     7 public:
     8     void func1() { };
     9     void  func2() { };
    10     void  func3() { };
    11 };
    12 
    13 int main()
    14 {
    15     A obj;
    16     int nLen = sizeof(obj);
    17     cout << nLen << endl; //sizeof(一个空类)为什么等于1?
    18 
    19     return 0;
    20 }

    此时给类A添加了三个成员函数,此时的类A对象的大小是多少呢?

     

    我们看到此时类A对象obj的大小还是1,说明类的成员函数不占用类对象的内存空间

     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 class A
     6 {
     7 public:
     8     void func1() { };
     9     void  func2() { };
    10     void  func3() { };
    11     char ab;
    12 };
    13 
    14 int main()
    15 {
    16     A obj;
    17     int nLen = sizeof(obj);
    18     cout << nLen << endl; //
    19 
    20     obj.ab = 'c';
    21     return 0;
    22 }

    我们添加了类A的成员变量ab之后,类A对象的大小是多大呢?

    我们看到类A对象obj的大小是1.shift+F9我们获取到obj的内存地址

    当断点走过obj.ab = 'c'这条赋值语句之后

    可以看到原来0bj的内存地址上存储了63这个十六进制,而十六进制63对应的ASCII码刚好是字符c,所以说是一个字节大小。同时也说明了成员变量占用类对象的内存空间

     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 class A
     6 {
     7 public:
     8     void func1() { };
     9     void  func2() { };
    10     void  func3() { };
    11     //char ab;
    12     int nab;
    13 };
    14 
    15 int main()
    16 {
    17     A obj;
    18     int nLen = sizeof(obj);
    19     cout << nLen << endl; //
    20 
    21     //obj.ab = 'c';
    22     obj.nab = 12;
    23     return 0;
    24 }

    输出结果为:

    打断点看到obj的内存地址是0x00cff9b4。而我们可以看到类A的成员变量是占用了4个字节来存储数据的。

     我们再来看一个例子:

     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 class A{};
     6 class B{};
     7 class C : public A 
     8 {
     9     virtual void func() = 0;
    10 };
    11 
    12 class D : public B, public C 
    13 {
    14 
    15 };
    16 
    17 int main()
    18 {
    19     cout << sizeof(A) << endl;
    20     cout << sizeof(B) << endl;
    21 
    22     cout << sizeof(C) << endl;
    23     cout << sizeof(D) << endl;
    24 
    25     return 0;
    26 }

    输出结果为:

     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 class A{};
     6 class B1{};
     7 class B 
     8 {
     9     char c;
    10 };
    11 class C : public A 
    12 {
    13     virtual void func() = 0;
    14 };
    15 
    16 class D : public B, public C {};
    17 
    18 class E :public B1, public C {};
    19 int main()
    20 {
    21     cout << sizeof(A) << endl;
    22     cout << sizeof(B) << endl;
    23 
    24     cout << sizeof(C) << endl;
    25     cout << sizeof(D) << endl;
    26     cout << sizeof(E) << endl;
    27 
    28     return 0;
    29 }

    输出结果:

    类A,B的大小为1上面我们已经讲过原因,而类C是由类A派生出来的,它里面有一个纯虚函数,由于有虚函数的原因,有一个指向虚函数的指针(vptr),在32位的系统分配给指针的大小为4个字节,所以最后得到类C的大小为4个字节(类里只要有一个虚函数,或者说至少有一个虚函数,这个类就会产生一个指向虚函数的指针,有两个虚函数就会产生两个指向虚函数的指针,类本身,指向虚函数的指针(一个或者一堆)要有地方存放,这些指针就存放在一个表格里,这个表格我们称为“虚函数表”,这个虚函数表是保存在可执行文件中的,在程序执行的时候载入到内存中来。不管有几个虚函数,在32位的系统sizeof()都是多了4个字节)

    类D的大小更让初学者疑惑,类D是由类B,C派生而来的,它的大小应该为二者之和5,为什么是8呢?这是因为为了提高实例在内存中的存取效率,类的大小往往被调整到系统的整数倍,并采取就近的法则,离哪个最近的倍数,就是该类的大小,所以类D的大小为8个字节。

    下面我们再看一个例子:

     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 class A
     6 {
     7 private:
     8     int data;
     9 };
    10 
    11 class B
    12 {
    13 private:
    14     int data;
    15     static int xs;
    16 };
    17 int B::xs = 10;
    18 int main()
    19 {
    20     cout << sizeof(A) << endl;
    21     cout << sizeof(B) << endl;
    22 
    23     return 0;
    24 }

    输出结果为:

    为什么类B比类A多了一个数据成员,大小却和类A的大小相同呢?因为类B的静态数据成员被编译器放在程序的一个global data members中,它是类的一个数据成员,但是它不影响类的大小,不管这个类实际产生了多少实例,还是派生了多少新的类,静态成员在类中只有一个实体存在,而类的非静态数据成员只有被实例化的时候,他们才存在,但是类的静态数据成员一旦被声明,无论类是否被实例化,它都已经存在,可以这么说,类的静态数据成员是一种特殊的全局变量。

    下面我们看一个有构造函数,和析构函数的类的大小,它又是多大呢?

     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 class A
     6 {
     7 public:
     8     A(int a) { x = a;  }
     9     void func() 
    10     {
    11         cout << x << endl;
    12     }
    13 
    14     ~A() { }
    15 private:
    16     int x;
    17     int g;
    18 };
    19 
    20 class B 
    21 {
    22 public:
    23 private:
    24     int a;
    25     int b;
    26     static int xs;
    27 };
    28 
    29 int B::xs = 20;
    30 
    31 int main()
    32 {
    33     A a(10);
    34     //a.func();
    35 
    36     B b;
    37     cout << sizeof(a) << endl;
    38     cout << sizeof(b) << endl;
    39     return 0;
    40 }

    它们的结果均相同,可以看出类的大小与它当中的构造函数,析构函数,以及其他的成员函数无关,只与它当中的成员数据有关.

    从以上几个例子我们可以总结出来类的大小

    1.为类的非静态成员数据的类型大小之和.
    2.由编译器额外加入的成员变量的大小,用来支持语言的某些特性(如:指向虚函数的指针). 
    3.为了优化存取效率,进行的边缘调整(字节对齐). 
    4 与类中的构造函数,析构函数以及其他的成员函数无关.

    另外:一个类对象至少占用1个字节的内存空间。

  • 相关阅读:
    文件重名问题
    文件上传
    回顾IO流
    Freemarker
    中文乱码问题
    Filter(过滤器)
    Ajax
    jQuery
    普华操作系统,开机无法进入桌面程序; 解决多次source /etc/profile的烦恼
    C++ 文件类型判别错误,将目录文件识别为普通文件
  • 原文地址:https://www.cnblogs.com/cxq0017/p/10643466.html
Copyright © 2020-2023  润新知