深入分析C++中类的大小

2016-02-19 10:04 2 1 收藏

下面,图老师小编带您去了解一下深入分析C++中类的大小,生活就是不断的发现新事物,get新技能~

【 tulaoshi.com - 编程语言 】

首先看一个例子:
代码如下:

#include iostream
 using namespace std;

 class A{};

 class B
 {
     int b;
     char c;
 };

 class C
 {
     int c1;   
     static int c2;
 };
 int C::c2 = 1;

 class D:public C,public B{
     int d;
 };
 int main()
 {
     cout"sizeof(A)="sizeof(A)endl;
     cout"sizeof(B)="sizeof(B)endl;
     cout"sizeof(C)="sizeof(C)endl;
     cout"sizeof(D)="sizeof(D)endl;

     return 0;
 }

运行结果为:

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

sizeof(A)=1

sizeof(B)=8

sizeof(C)=4

sizeof(D)=16

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

对于类A来说,虽然A是一个空类,但为了便于空类进行实例化,编译器往往会给它分配一个字节,这样A实例化后便在内存中有了一个独一无二的地址.对于类B,B的大小应为sizeof(int)+sizeof(char)=5,但是考虑内存对齐,B的大小应为8.对于类C,类的静态成员变量被放在全局区,和类的普通成员并没有放在一块。类的静态成员被声明后就已存在,而非静态成员只有类被实例化后才存在。所以C的大小为sizeof(int)=4。D的大小为B+C的大小+自身数据成员的大小,一共为16.

==========================分割线在这里====================================

下面讨论含有虚函数的类的大小:
代码如下:

#include iostream
 using namespace std;

 class A
 {
 public:
     void virtual aa(){};
 };

 class B:public A
 {
     void virtual bb(){};
 };

 class C:virtual A
 {
 public:
     void virtual aa(){};
     void cc(){};
 };

 class D:virtual A
 {
 public:
     void virtual dd(){};
 };

 int main()
 {
     cout"sizeof(A)="sizeof(A)endl;
     cout"sizeof(B)="sizeof(B)endl;
     cout"sizeof(C)="sizeof(C)endl;
     cout"sizeof(D)="sizeof(D)endl;

     return 0;
 }

运行结果为:

sizeof(A)=4

sizeof(B)=4

sizeof(C)=8

sizeof(D)=12

对于class A,它含有一个虚函数,编译器会为虚函数生成一张虚函数表,来记录对应的函数地址,为此,在class A的内存地址中要有一个vfptr_A指针指向这个虚表,所以class A的大小为指针大小,即4.(注意,无论类中有多少个虚函数,它们的大小都是4,因为内存中只需要保存这个指针即可)。

对于class B,它是public继承A,虽然它也有一个虚函数,但是从结果看,B应该和A都在B的vtable(虚表中),所以class B的大小为4.

对于class C,它是vitual 继承A,所以要有一个指向父类A的指针,占有4字节大小aa()是继承自class A的虚函数,从结果来看,它没有在内存中占有空间,所以C的大小为sizeof(A)+4=8.

对于class D,它是虚继承class A,同上,要有一个指向父类A的指针,同时,class D中有虚函数,所以要有一个指向虚表的指针,所以sizeof(D)=sizeof(A)+4+4=12

来源:https://www.tulaoshi.com/n/20160219/1593221.html

延伸阅读
1.源程序的编译     在Linux下面,如果要编译一个C语言源程序,我们要使用GNU的gcc编译器. 下面我们以一个实例来说明如何使用gcc编译器. 假设我们有下面一个非常简单的源程序(hello.c):  int main(int argc,char **argv)   { printf("Hello Linux/n");   } 要编译这个程序,我们只要在命令行下执行: gcc -o h...
一.创建DLL 1.在VC中新建一个Win32空项目MathLib; 2.添加预编译头文件stdafx.h,定义导入导出控制符号: 代码如下: //stdafx.h #pragma once #define MATHLIB_EXPORT 3.添加包含要导出的全局变量,函数和类的头文件MathLib.h: 代码如下:  //MathLib.h  #pragma once  #ifdef MATHLIB_EXPORT  #define MATHLIBAPI __...
Java中使用的路径,分为两种:绝对路径和相对路径。 归根结底,Java本质上只能使用绝对路径来寻找资源。所有的相对路径寻找资源的方法,都不过是一些便利方法。不过是API在底层帮助我们构建了绝对路径,从而找到资源的! 在开发Web方面的应用时, 经常需要获取 服务器中当前WebRoot的物理路径。 如果是Servlet , Action , Controller, 或则Filte...
我们经常在项目中使用继承,但是往往不太明白,程序运行的顺序以及原理,尤其是使用上转型对象的时候,以及父类子类中都有static变量和方法时,不知道先运行谁。我也是写了一个例子。总结了一下。 代码如下: 父类: public class TestStatic {     public static String name="china";     {   &...
Android 系统在Activity 生命周期中加入一些钩子,我们可以在这些系统预留的钩子中做一些事情。 例举了 7 个常用的钩子: protected void onCreate(Bundle savedInstanceState) protected void onStart() protected void onResume() protected void onPause() protected void onStop() protected void onRestart() protected void onDes...

经验教程

663

收藏

5
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部