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

2016-02-19 10:04 4 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;
 }

运行结果为:

sizeof(A)=1

sizeof(B)=8

sizeof(C)=4

sizeof(D)=16

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

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

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

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

#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;
 }

运行结果为:

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

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

来源:http://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...
Java中使用的路径,分为两种:绝对路径和相对路径。 归根结底,Java本质上只能使用绝对路径来寻找资源。所有的相对路径寻找资源的方法,都不过是一些便利方法。不过是API在底层帮助我们构建了绝对路径,从而找到资源的! 在开发Web方面的应用时, 经常需要获取 服务器中当前WebRoot的物理路径。 如果是Servlet , Action , Controller, 或则Filte...
一.创建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 __...
我们经常在项目中使用继承,但是往往不太明白,程序运行的顺序以及原理,尤其是使用上转型对象的时候,以及父类子类中都有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...

经验教程

127

收藏

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