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

首先看一个例子:


代码如下:

#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.

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

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


代码如下:

#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

(0)

相关推荐

  • C++空类及没有成员变量的类的大小实例分析

    众所周知的C++中空类的大小为1,但是除了空类之外的其他一些没有成员变量的类的大小,还是有相当一部分开发人员对此有很多不明之处的. 这里我们以如下代码为例: #include using namespace std; class a {}; class b{}; class c :public a{ virtual void fun() = 0; }; class d :public b, public c{}; int main() { cout << "sizeof(a)&quo

  • C++空类默认函数详细解析

    定义一个空的C++类,例如 class Empty{} 一个空的class在C++编译器处理过后就不再为空,编译器会自动地为我们声明一些member function,一般编译过去就相当于 复制代码 代码如下: class Empty{public:Empty(); // 缺省构造函数Empty( const Empty& ); // 拷贝构造函数~Empty(); // 析构函数Empty& operator=( const Empty& ); // 赋值运算符Empty* op

  • c语言获取文件大小的示例

    1.fseek 函数原型: 复制代码 代码如下: int fseek ( FILE * stream, long int offset, int origin ); 参数说明:stream,文件流指针:offest,偏移量:orgin,原(始位置.其中orgin的可选值有SEEK_SET(文件开始).SEEK_CUR(文件指针当前位置).SEEK_END(文件结尾). 函数说明:对于二进制模式打开的流,新的流位置是origin + offset. 2.ftell 函数原型:long int ft

  • c++动态内存空间示例(自定义空间类型大小和空间长度)

    动态内存空间的申请示范 利用C++的特性,能够自定义空间的类型大小和空间长度 下面这个程序是个数组动态配置的简单示例 复制代码 代码如下: #include <iostream>using namespace std; int main(){   int size = 0; cout << "请输入数组长度:";  //能够自定义的动态申请空间长度    cin >> size;    int *arr_Point = new int[size];

  • C++空类详解

    空类默认产生的成员:class Empty {};Empty(); // 默认构造函数Empty( const Empty& ); // 默认拷贝构造函数~Empty(); // 默认析构函数Empty& operator=( const Empty& );  // 默认赋值运算符Empty* operator&();               // 取址运算符const Empty* operator&() const;    // 取址运算符 const 给出

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

    首先看一个例子: 复制代码 代码如下: #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<<"s

  • C++对象内存分布详解(包括字节对齐和虚函数表)

    1.C++对象的内存分布和虚函数表: C++对象的内存分布和虚函数表注意,对象中保存的是虚函数表指针,而不是虚函数表,虚函数表在编译阶段就已经生成,同类的不同对象中的虚函数指针指向同一个虚函数表,不同类对象的虚函数指针指向不同虚函数表. 2.何时进行动态绑定: (1)每个类对象在被构造时不用去关心是否有其他类从自己派生,也不需要关心自己是否从其他类派生,只要按照一个统一的流程:在自身的构造函数执行之前把自己所属类(即当前构造函数所属的类)的虚函数表的地址绑定到当前对象上(一般是保存在对象内存空间

  • Python面向对象程序设计中类的定义、实例化、封装及私有变量/方法详解

    本文实例讲述了Python面向对象程序设计中类的定义.实例化.封装及私有变量/方法.分享给大家供大家参考,具体如下: 1. 定义类 python中定义一个类的格式如下: class MyClass(object): def __init__(self,data1,data2): self.__data1=data1 self.data2=data2 def __func1(self): print("MyClass类的私有方法被调用!") def print_data(self): s

  • 深入理解Objective-C中类的数据结构

    一.类的结构 OC 中的代码在底层实现,使用的是 C.C++,所以要研究 OC 中的类结构,可以将 OC 的代码转成 C++的代码即可.首先看一下 NSObject 的结构是什么样子的,创建一个文件并简单的编写如下代码: // CustomFile.m #import <Foundation/Foundation.h> void test() { [NSObject alloc]; } 进入终端,输入指令: clang -rewrite-objc CustomFile.m 默认生成一个 Cus

  • Objective-C中关于实例所占内存的大小详解

    前言 续上一篇文章的介绍,这篇文章就诞生可.建议先看Objective-C 中类的数据结构,因这两部分的内容是不能断的,建议先去看看. 接下来的主题是 Objective-C 中实例所占内存的大小. 以下都是以 64bit 上分析的. 一.instance 所占内存的大小 先定义这样的一个 Class: // 类的申明 @interface SizeObject : NSObject { @private int _no; // int _age; } @end // 类的实现 @impleme

  • 彻底搞懂 python 中文乱码问题(深入分析)

    前言 曾几何时 Python 中文乱码的问题困扰了我很多很多年,每次出现中文乱码都要去网上搜索答案,虽然解决了当时遇到的问题但下次出现乱码的时候又会懵逼,究其原因还是知其然不知其所以然.现在有的小伙伴为了躲避中文乱码的问题甚至代码中不使用中文,注释和提示都用英文,我曾经也这样干过,但这并不是解决问题,而是逃避问题,今天我们一起彻底解决 Python 中文乱码的问题. 基础知识ASCII 很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物.他们看到8个开关

  • SQL查询的底层运行原理深入分析

    前言 SQL 语言无处不在.SQL 已经不仅仅是技术人员的专属技能了,似乎人人都会写SQL,就如同人人都是产品经理一样.如果你是做后台开发的,那么CRUD就是家常便饭.如果你是做数仓开发的,那么写SQL可能占据了你的大部分工作时间.我们在理解 SELECT 语法的时候,还需要了解 SELECT 执行时的底层原理.只有这样,才能让我们对 SQL 有更深刻的认识.本文分享将逐步分解SQL的执行过程,希望对你有所帮助. 数据准备 本文旨在说明SQL查询的执行过程,不会涉及太复杂的SQL操作,主要涉及两

  • 深入分析C++模板特化与偏特化

    1.模板特化 1.1概述 模板特化(template specialization)不同于模板的实例化,模板参数在某种特定类型下的具体实现称为模板的特化.模板特化有时也称之为模板的具体化,分别有函数模板特化和类模板特化. 1.2函数模板特化 函数模板特化是在一个统一的函数模板不能在所有类型实例下正常工作时,需要定义类型参数在实例化为特定类型时函数模板的特定实现版本.查看如下例子. #include <iostream> using namespace std; template<type

  • 深入分析mysql为什么不推荐使用uuid或者雪花id作为主键

    前言:在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究竟有什么坏处?本篇博客我们就来分析这个问题,探讨一下内部的原因. 一:mysql和程序实例 1.1:要说明这个问题,我们首先来建立三张表,分别是user_auto_key,user_uuid,user_random_key,分别表示自动增长的主键,uuid作为主键,随机

  • 多维度深入分析Redis的5种基本数据结构

    目录 一.简介 二.string(字符串) 1.string(字符串)相关介绍 1.1 string(字符串)的内部结构 1.2 string(字符串)的扩容 2.string(字符串)的指令 2.1 单个键值对增删改查操作 2.2 批量键值对 2.3 过期set命令 2.4 不存在创建存在不更新 2.5计数 三.list(列表) 1.list(列表)相关介绍 1.1 list(列表)的内部结构 1.2 list(列表)的使用场景 2.list(列表)的指令 2.1 右进左出-队列 2.2 右进

随机推荐