概述

在实际生产中,遇到一个复杂的类,如果能看出这个类的内存模型结构,那么以后的操作基本就没有难度的;

所以说,学会分析一个类的内存模型,是每一个C++程序员必须要会的知识。

下面,就让我们来了解C++对象模型!


C++类封装和C中的结构体的区别

C++的类封装是在C语言中的结构体的基础上构建起来的,C结构体只允许存在数据,而不会存在对数据的操作。

C++语言中延承C语言中的结构体,但增加的对数据的操作,即成员函数;

类是对结构体的进一步封装,使某些数据成员对外不可见,称为私有成员。

类和结构体最大的区别就是:结构体成员均是public类型的。

那么,类和结构体的布局成本有没有区别呢?

对于只有数据成员的类和结构体在内存的布局是相同的,没有增加成本。

而members functions 虽然含在class的声明之内,却不出现在object之中。每一个 non-inline member fuction 只会诞生一个函数实体,调用时链接至函数体。至于每一个"拥有零个或一个定义"的 inline function 则会在其每一个调用者(模块)身上产生一个函数实体。

在C++中,有两种 class data members: static 和 nonstatic,以及三种 class member functions : static、nonstatic 和 virtual。

在C++对象模型中,非静态数据成员被配置在每一个 class object 之内,静态数据成员则被存在个别的 class object 之外,静态和非静态的成员函数也被放在个别的 class object 之外。

C++在布局及存取时间上主要的额外负担是由 virtual 引起。包括:

  1. virtual function 机制:用以支持一个有效率的"执行期绑定"
  2. virtual base class 用以实现"多次出现在集成体系中的base class,有一个单一而被共享的实体。

虚函数以及虚函数表

无论是含有虚函数还是虚拟继承,类都会产生一个虚函数表,同时每一个对象都会含有一个Vptr指针指向虚拟函数表。

虚拟函数的实现

1.每一个 class 产生一堆指向虚函数的指针,放在表格之中,这个表格被称为 virtual table(vtbl)

2.每一个 class object 被安插一个指针,指向相关的 virtual table。这个指针通常被称为 vptr。vptr 的设定和重置都由每一个类的构造函数、析构函数和赋值操作符重载函数自动完成且一旦完成初始化不能修 改。每一个类所关联的type_info object(主要用于RTTI)也经由 virtual table被指出来,通常放在表格的第一个slot。


多重继承模型

C++最初采用的继承模型时间基类对象中的数据成员直接存放在继承类对象内存中,包括基类对象的虚函数表和虚指针(貌似现在也是这样的模型),这样就可以对基类成员进行最有效率的存取,然而缺点是如果基类成员有任何的修改将会导致基类对象和继承类对象的重新编译。

有人提出一种间接存取模型:在继承类对象中放置一指针Bptr,该指针指向继承类的基类表,类似与虚函数表,基类表中每一项都指向继承类对象的基类 对象。这样的好处是,基类对象的任何改变吗都不会影响到继承类对象的内存布局,缺点是导致对基类对象成员的存取效率低,随着继承深度的增加,间接性越强, 效率越低。

因此又有人提出,在继承类对象中放置与基类相等数目的指针指向每个基类,这样存取时间就恒久不变了,但是这样无疑增加了继承类的内存开销。

目前使用的多重继承模型仍为第一种,继承类对象中含有所有基类对象数据成员和虚指针,同时继承基类的虚函数表共享为继承类的虚函数表。


虚拟继承模型

虚拟继承保证继承类中只含有一个基类对象,继承类中会产生虚指针指向虚表中offset指向继承类中的基类对象。只有直接虚继承的继承类对象才会产生Vptr。

目前,关于虚拟继承的继承类的内存布局有三种模型:

1、原始模型:在每个继承类对象中设置指针,用以指向继承类中的基类对象。优点:通过指针能够保证继承类中只有一个基类对象,可以直接存取基类对象。缺点:若继承类有多个虚拟基类,则需要多个指针指向基类们,会消耗较多的内存。

2、有人提出像虚函数表一样,提供一个虚拟基类表virtual base class table,表中每个slot指向一个基类对象的地址。在继承类对象中,设置一个虚拟基类表指针指向基类表。优点:继承类减少了因虚拟基类指针而产生的开 销,且继承类不会因为虚拟基类的增加而改变内存模型。缺点:存取基类对象数据成员会导致效率低下。

3、现在最常用的模型:扩充原Virtual table,在虚表负offset位置指向虚基类对象,因此,只要是虚继承就会产生虚指针和虚表。

虚拟多继承,采用“钻石”继承结构,其每个类的内存分布如下图:其中虚指针的位置可以在顶部或尾部。

上述内容是类对象内存模型的介绍:

(1)无虚函数和虚继承:nostatic数据成员存放在对象中,static数据成员存放在对象外属于整个类。nostatic和static函数成员均放在对象外。

(2)有虚函数和虚继承:virtual函数放在虚函数表中,通过虚指针进行查找调用。基类对象数据成员和虚指针均存放在继承类的对象中。

深入探索C++对象模型-1的更多相关文章

  1. 读书笔记《深度探索c++对象模型》 概述

    <深度探索c++对象模型>这本书是我工作一段时间后想更深入了解C++的底层实现知识,如内存布局.模型.内存大小.继承.虚函数表等而阅读的:此外在很多面试或者工作中,对底层的知识的足够了解也 ...

  2. 柔性数组-读《深度探索C++对象模型》有感 (转载)

    最近在看<深度探索C++对象模型>,对于Struct的用法中,发现有一些地方值得我们借鉴的地方,特此和大家分享一下,此间内容包含了网上搜集的一些资料,同时感谢提供这些信息的作者. 原文如下 ...

  3. 柔性数组-读《深度探索C++对象模型》有感

    最近在看<深度探索C++对象模型>,对于Struct的用法中,发现有一些地方值得我们借鉴的地方,特此和大家分享一下,此间内容包含了网上搜集的一些资料,同时感谢提供这些信息的作者. 原文如下 ...

  4. [读书系列] 深度探索C++对象模型 初读

    2012年底-2014年初这段时间主要用C++做手游开发,时隔3年,重新拿起<深度探索C++对象模型>这本书,感觉生疏了很多,如果按前阵子的生疏度来说,现在不借助Visual Studio ...

  5. 拾遗与填坑《深度探索C++对象模型》3.3节

    <深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...

  6. 拾遗与填坑《深度探索C++对象模型》3.2节

    <深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...

  7. 深度探索C++对象模型

    深度探索C++对象模型 什么是C++对象模型: 语言中直接支持面向对象程序设计的部分. 对于各个支持的底层实现机制. 抽象性与实际性之间找出平衡点, 需要知识, 经验以及许多思考. 导读 这本书是C+ ...

  8. 《深度探索C++对象模型》读书笔记(一)

    前言 今年中下旬就要找工作了,我计划从现在就开始准备一些面试中会问到的基础知识,包括C++.操作系统.计算机网络.算法和数据结构等.C++就先从这本<深度探索C++对象模型>开始.不同于& ...

  9. C++的黑科技(深入探索C++对象模型)

    周二面了腾讯,之前只投了TST内推,貌似就是TST面试了 其中有一个问题,“如何产生一个不能被继承的类”,这道题我反反复复只想到,将父类的构造函数私有,让子类不能调用,最后归结出一个单例模式,但面试官 ...

  10. 深入探索C++对象模型(一)

    再读<深入探索C++对象模型>笔记. 关于对象 C++在加入封装后(只含有数据成员和普通成员函数)的布局成本增加了多少? 答案是并没有增加布局成本.就像C struct一样,memeber ...

随机推荐

  1. 使用Raphael 画图(四) 路径(一) (javascript)

    这章介绍路径,本人觉得这是比较难和精髓的一部分. 先介绍基本知识: 可以参考: http://www.chinasvg.com/support/svg-tutorial/svg-path-direct ...

  2. jQuery网页加载进度条插件

    jquery.pace.js会自动监测你的Ajax请求,事件循环滞后,记录您的页面上准备状态和元素来决定的进度情况. 将pace.js和主题css的添加到您的网页! pace.js会自动监测你的Aja ...

  3. K - 计算球体积

    Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u   Description 根据输入的 ...

  4. 重装Ubuntu系统并配置开发环境

    安装 Ubuntu 并配置开发环境 写一篇文章详细记录下来所有的过程,以便以后参考. 安装前的准备 备份所有代码和配置文件 备份下载的各类文件 Ubuntu 安装 下载安装 Ubuntu14.04,下 ...

  5. [UOJ Round#4 A] [#51] 元旦三侠的游戏 【容斥 + 递推】

    题目链接:UOJ - 51 据说这题与 CF 39E 类似. 题目分析 一看题目描述,啊,博弈论,不会!等待爆零吧... 这时,XCJ神犇拯救了我,他说,这题可以直接搜啊. 注意!是用记忆化搜索,状态 ...

  6. 【Java】Java XML 技术专题

    XML 基础教程 XML 和 Java 技术 Java XML文档模型 JAXP(Java API for XML Parsing) StAX(Streaming API for XML) XJ(XM ...

  7. c# 类;一维数组;二维数组

    1. 输入邮箱帐号,判断格式是否正确  (1)有且只有一个@          Contains IndexOf ==LastIndexOf  (2)不能以@开头           StartsWi ...

  8. HDNOIP201206施工方案

    HDNOIP201206施工方案 难度级别:A: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 c国边防军在边境某处的阵地是由n个地堡组成的. ...

  9. Redis Sentinel实现Failover

    redis版本:2.8.17   服务器规划: 10.50.13.34(6379 master) 10.50.13.35(6379 slave) 10.50.13.36(6379 slave) 10. ...

  10. 图论(网络流):[SDOI2010] 星际竞速

    Description 10 年一度的银河系赛车大赛又要开始了.作为全银河最盛大的活动之一,夺得这个项目的冠军无疑是很多人的梦想,来自杰森座 α星的悠悠也是其中之一. 赛车大赛的赛场由 N 颗行星和M ...