C++对象及多态实现探索之内存布局

C++ 对象内存布局和多态实现原理 进入主题前,先把工具设置好。本文使用编译测试环境:Visual Studio 2013 VS2013查看类内存布局设置方式如下截图: 先选择左侧的C/C++->命令行,然后在其他选项这里写上/d1 reportAllClassLayout,它可以看到所有相关类的内存布局,如果写上/d1 reportSingleClassLayoutXXX(XXX为类名),则只会打出指定类XXX 阅读详情
普通类对象的内存布局

首先我们从普通类对象的内存布局开始。C000为一个空类,定义如下:

struct C000
{};

运行如下代码打印它的大小及对象中的内容。

PRINT_SIZE_DETAIL(C000)

结果为:

The size of C000 is 1

The detail of C000 is cc

可以看到它的大小为1字节,这是一个占位符。我们可以看到它的值是0xcc。在debug模式下,这表示是由编译器插入的调试代码所初始化的内存。在release模式下可能是个随机值,我测试时值为0x00。

定义两个类,C010和C011如下:

struct C010
{

 C010() : c_(0x01) {}

 void foo() { c_ = 0x02; }

 char c_;

};

struct C011
{

 C011() : c1_(0x02), c2_(0x03) {}

 char c1_;

 char c2_;

};

运行如下代码打印它们的大小及对象中的内容。

PRINT_SIZE_DETAIL(C010)

PRINT_SIZE_DETAIL(C012)

结果为:

The size of C010 is 1

The detail of C010 is 01

The size of C011 is 2

The detail of C011 is 02 03

我们从对象的内存输出中可以看到,它们的值就是我们在构造函数中赋的值,C010为0x01,C011为0x0203。大小分别为1、2。

定义C012类。

struct C012
{

 static int sfoo() { return 1; }

 int foo() { return 1; }

 char c_;

 static int i_;

};

int C012::i_ = 1;

在这个类中我们加入了一个静态数据成员,一个普通成员函数和一个静态成员函数。

运行如下代码打印它的大小及对象中的内容。

PRINT_SIZE_DETAIL(C012)

结果为:

The size of C012 is 1

The detail of C012 is cc

可以看到它的大小还是1字节,值为0xcc是因为我们没有初始化它,原因前面说过了。

从上面的结果我们可以映证,普通成员函数,静态成员函数,及静态成员变量皆不会在类的对象中有所表示,成员函数和对象的关联由编译器在编译时处理,正如我们会在后面看到的那样,编译器会在编译时决议出正确的普通成员函数地址,并将对象的地址以this指针的方式,做为第一个参数传递给普通成员函数,以此来进行关联。静态成员函数类似于全局函数,不和具体的对象关联。静态成员变量也一样。静态成员函数和静态成员变量和普通的全局函数及全局变量不同之处在于它们多了一层名字限定。

普通继承类对象的内存布局

下面看看普通继承类对象的内存布局。

定义一个空类C014从C011继承,再定义C015也是一个空类从C010和C011继承。

struct C010
{

 C010() : c_(0x01) {}

 void foo() { c_ = 0x02; }

 char c_;

};

struct C011
{

 C011() : c1_(0x02), c2_(0x03) {}

 char c1_;

 char c2_;

};

struct C014 : private C011
{};

struct C015 : public C010, private C011
{};

运行如下代码打印它们的大小及对象中的内容。

PRINT_SIZE_DETAIL(C014)

PRINT_SIZE_DETAIL(C015)

结果为:

The size of C014 is 2

The detail of C014 is 02 03

The size of C015 is 3

The detail of C015 is 01 02 03

C014的大小为2字节,也就是C011的大小,对象的内存值也是在C011的构造函数中初始化的两个值0x0203。C015的大小为3字节,也就是C010和C011的大小之和,对象的内存值为0x010203。

这里我们可以发现父类的成员变量悉数被子类继承,并且于继承方式(公有或私有)无关,如C015是私有继承自C011。继承方式只影响数据成员的“能见度”。子类对象中属于从父类继承的成员变量由父类的构造函数初始化。通常会调用默认构造函数,除非子类在它的构造函数初始化列表中显式调用父类的非默认构造函数。如果没有指定,而父类又没有缺省构造函数,则会产生编译错误。

我们可以再加一层继承来验证一下。定义类C016,从C015继承,并有自己的4字节int成员变量。

struct C016 : C015
{

 C016() : i_(1) {}

 int i_;

};

运行如下代码打印它的大小及对象中的内容。

PRINT_SIZE_DETAIL(C016)

结果为:

The size of C016 is 7

The detail of C016 is 01 02 03 01 00 00 00

它的大小为7字节,也就是C015的大小(也即是C010和C011的大小和)加上自身的4字节int变量之和。同样对象的内存输出也验证了这一点,前三个字节为从父类继承的,后4个字节为自身的int变量,值为1。

因此关于普通继承,子类的对象布局为父类中的数据成员加上子类中的数据成员,多层继承时(如C016),顶层类在前,多重继承时则最左父类在前。
《深度探索c++内存模型》读书笔记 (一) 第一章 关于对象前言加上封装后的布局成本c++对象模式加上继承C++中的多态对象所占用的内存大小指针的类型加上多态之后 前言 在C语言里面,数据和函数是分开的,它们之间的关联是通过参数和返回值来取得联系。如: typedef struct point3d { float x; float y; float z; } Point3d; void print_point3d(const Point3d *p) { printf("%g %g %g", p->x, p 阅读详情

相关推荐

C++对象模型:g++的实现(一)

本文章向大家介绍C++对象模型:g++的实现(一),主要内容包括无继承情况下的C++对象内存布局、无虚函数、有虚函数、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

wuxiaopengnihao1的博客 478

c++ 多态内存布局分析

前言 上节对分析了多态的基本概念, 本节从内存布局的角度再来分析一下多态吧。 单一继承的内存布局 最开始我们分析了虚指针, 虚表, 但都只停留在单继承中, 现在我们在来扩展的探讨多重继承的内存布局 #include <iostream> #include <stdlib.h> #include <cstring> #include <functional&

啦啦啦 2043

咱们一起学C++ 第二百一十三篇之揭开C++虚函数背后的神秘面纱

大家好!C++中的虚函数就像是一个神秘的宝藏,看似难以捉摸,但一旦深入了解,就能发现它强大的功能和魅力。今天咱们就一起深入探索虚函数背后的原理,希望在这个过程中,大家都能收获满满,共同进步!

wj_rdk的博客 1118

c++多态情况下对象内存布局

今天在复习C++多态时有个问题没弄清楚,子类继承含有虚函数的父类时,子类的虚表是否是公用的?如果是公用的,虚表什么时候创建?为了弄清楚这个问题,写了以下程序来验证。得到了如下结论: 子类的虚表是公用,虚表创建于第一个实例构造之时,所有子类实例虚表指针都指向这块虚表。同时也验证了C++对象的内存布局 以下是验证代码: #include "stdafx.h" #include usin

zhang2531的专栏 990

C语言获取硬件信息(CPU序列号,硬盘序列号,网卡IP、MAC地址、是否插入网线)

本文主要介绍Linux和Windows下使用C语言获取各种硬件信息,包括CPU序列号、硬盘序列号、网卡信息(包括网卡名字、IP地址、MAC地址、网卡是否插入网线等)。

叶落花枯的博客 9378

ENVI5.3.1使用Landsat 8影像进行辐射定标和大气校正实例操作

ENVI5.3.1使用Landsat 8影像进行辐射定标和大气校正实例操作

PeanutbutterBoh的博客 12万+

C++多态和对象的内存布局(三)

续 C++多态和对象的内存布局(一) C++多态和对象的内存布局(二) 9. 普通多继承不存在函数覆盖,各自有各自的虚函数 程序输出: sizeof(Base_1) = 12 sizeof(Base_2) = 12 sizeof(Derive_1) = 32 (为什么只有32大小?难道Derive类对象没有虚函数指针???看第十条分析) Base1内存布局: 1> cla...

SSSS的博客 479

19-5 ACC 自适应巡航控制系统需求

本专题由深圳季连AIgraphX李博及团队出品,主要讲解ACC自适应巡航控制系统的开发与仿真测试。具体说来,包括ACC标准/法规分析、系统需求、系统架构、软件需求、软件架构、算法建模、验证场景分析、仿真实验搭建等内容。 本节主要讲ACC系统需求。

AIgraphX 1088

C++多态和对象的内存布局(一)

首先VS2015配置: 在当前工程右键 --> 属性: 先选择左侧的C/C++->命令行,然后在其他选项这里写上/d1 reportAllClassLayout,它可以看到所有相关类的内存布局,如果写上/d1 reportSingleClassLayoutXXX(XXX为类名),则只会打出指定类XXX的内存布局。 开始进入主题测试类对象内存布局: 1. 只有数据...

SSSS的博客 1132

K-Means聚类算法 — 算法原理、质心计算、距离度量、聚类效果评价及优缺点

分类知识   分类是根据样本某些属性或某类特征(可以融合多类特征),把样本类型归为已确定的某一类别中。机器学习中常见的分类算法有:SVM(支持向量机)、KNN(最邻近法)、Decision Tree(决策树分类法)、Naive Bayes(朴素贝叶斯分类)、Neural Networks(神经网络法)等。   但当对海量数据进行分类时,为了降低数据满足分类算法要求所需要的预处理代价,往往需要选...

zhf的博客 1万+

FUEL算法解读(一)——框架解读,思维导图可以很清晰看懂算法启动框架,已更新完,图太大放不上来链接在文末

一图看懂FUEL算法节点框架!!!

weixin_43793717的博客 2785

C++对象布局及多态实现探索之内存布局(转载)

作者: 潘凯 前言   本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等。  写这篇文章源于我在论坛上看到的一个贴子。有人问VC使用了哪种方式来实现虚继承。当时我写了一点代码想验证一下,结果发现情况比我想象的要复杂。所以我就干脆认真把相关的问题都过了一遍,并记录成本文。  我对于C++对象模型的知识主要来自于Lippman的书《

LuWei 1214

使用LabVIEW创建和分析柱状图:从基础绘制到高级数据分析的完整指南

LabVIEW,全称为Laboratory Virtual Instrument Engineering Workbench,是由美国国家仪器公司(National Instruments, NI)开发的一款图形化编程语言。自1986年首次推出以来,LabVIEW凭借其强大的数据采集、分析和控制能力,在工程、科研、教育等领域得到了广泛应用。与传统的文本编程语言不同,LabVIEW采用了图形化编程方式,用户通过连接不同的函数节点来实现复杂的逻辑和算法。

qq_38334677的博客 775

C++对象布局及多态实现探索之内存布局

前言   本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等。  写这篇文章源于我在论坛上看到的一个贴子。有人问VC使用了哪种方式来实现虚继承。当时我写了一点代码想验证一下,结果发现情况比我想象的要复杂。所以我就干脆认真把相关的问题都过了一遍,并记录成本文。  我对于C++对象模型的知识主要来自于Lippman的书《Inside

枣子的IT专栏 2052

Asterisk中MixMonitor之支持接通后录音

一、概述 当我们使用开源的IPPBX(比如Elastix-2.5/4.0或者ISSABEL-4.0/FreePBX)的时候Outbound和Inbound路由(RingGroup/FollowMe)中有一个Call Recording选项,其值包括:Allow、Record immediately、Record On Answer和Nerver。当选择为Record On Answer,其实就是MixMonitor自带一个b选项。 尽管Asterisk自带的MixMoni...

宽简厚重—博约 1156

从 0 到 1 玩转小智 AI 智能音箱:开发教程 + 实战项目全攻略

如果说 MCP 是工具箱,那 SDK 就是 “技能模板”—— 小智音箱的自定义技能本质是 “意图识别 + 逻辑响应” 的组合,就像给嵌入式设备写驱动程序,只要按规则调用接口,就能实现各种功能。小智 AI 音箱的开发门槛并不高,核心是利用 MCP SDK 封装好的接口,结合嵌入式开发的 “硬件对接 + 逻辑编程” 思维,就能实现各种自定义功能。从环境搭建到技能开发,再到实战项目落地,每一步都是对 “软件控制硬件” 的实践 —— 而这正是嵌入式开发的核心魅力。

weixin_42300449的博客 1193

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yes

u012138828的专栏 702

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

【免费下载】 深度探索C++对象模型 PDF

深度探索C++对象模型 PDF 【下载地址】深度探索C对象模型PDF 深度探索C++对象模型 PDF欢迎来到《深度探索C++对象模型》PDF资源页面 项目地址: https://gitcode.com/open-source-to...

gitblog_09794的博客 784

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

深度探索C++对象模型(2012版本)

深度探索C++对象模型(2012版本) 【下载地址】深度探索C对象模型2012版本 深度探索C++对象模型(2012版本)欢迎来到《深度探索C++对象模型》(2012年版)的Git仓库页面 项目地址: https://gitcod...

gitblog_09768的博客 402

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

C++多态虚函数实现原理,对象和虚函数表的内存布局

基本概念 我们知道C++动态多态是用虚函数实现的,而虚函数的实现方式虽说C++标准没有要求,但是基本都是用虚函数表实现的(编译器决定)。所以我们有必要了解一下虚函数表的实现原理。 用virtual关键字声明的成员函数是虚函数。 具有虚函数的类及其派生的类会在编译时创建虚函数表,简称虚表(vtbl),虚表是虚函数指针的数组。 具有虚函数的类对象有一个虚表指针(vfptr),是编译器生成的指针,在对象构造时初始化。虚表指针vfptr指向虚表的第一个虚函数指针(即vfptr的值是虚表第一个...

回头太难 3707

c++多态,为何只能通过指针或引用实现

一览本文目的内存切割尾语 本文目的     在c++的多态中,如果一个基类的虚函数被派生类重写,那么把基类的指针指向派生类,就能够通过基类调用被派生类重写的这个虚函数。(对于这点有疑问的,可以看我之前写的C++多态,虚函数,虚函数表,gcc下的单继承,多继承,虚继承的内存布局)。那么如果不用指针或引用会如何? class Animal{ public: ...

Lupin 9136

C++对象的内存布局

本文介绍一个C++ struct/class在内存中的布局是什么样的,包括数据成员和方法成员,静态成员,非静态成员,虚拟成员在内存中的位置;本文不涉及(多)继承情况下对象内存布局的细节。

giantpoplar的专栏 4172

C++类对象在内存中的布局

目录 一、前言 二、C++ 类对象的内存布局 2.1 只有数据成员的对象 2.2 没有虚函数的对象 2.3 拥有仅一个虚函数的类对象 2.4 拥有多个虚函数的类对象 三、继承关系中的C++类对象内存分布 3.1 存在继承关系且本身不存在虚函数的派生类的内存布局 ​3.2本身不存在虚函数(不严谨)但存在基类虚函数覆盖的单继承类的内存布局 3.3 定义了基类没有的虚函数的单继承的类对象布局 3.4 多继承且存在虚函数覆盖同时又存在自身定义的虚函数的类对象布局 3.5如果第1个直接基...

qq_41687938的博客 3601

C++ 对象的内存布局

C++ 对象的内存布局是一个重要的概念,它影响着对象的存储、访问效率以及内存使用。理解对象的内存布局有助于优化程序性能和避免潜在的内存问题。以下是 C++ 对象内存布局的主要组成部分:数据成员是对象的状态表示,通常是类中定义的变量。数据成员的存储顺序通常是按照它们在类中声明的顺序排列。需要注意的是,编译器可能会在数据成员之间插入填充(padding),以满足对齐要求。对齐是指数据在内存中存储时的地址要求。不同类型的数据可能有不同的对齐要求。例如, 通常需要在 4 字节对齐的地址上存储,而 可能需要在 8

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 1057
上一篇: C++ virtual member function FAQ
下一篇: 怎样将成员函数指针强制转换成void*指针?
sharpdew
博客等级 码龄23年 76粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值