[转]深入探索C++对象模型(1)

在实际生产中,遇到一个复杂的类,如果能看出这个类的内存模型结构,那么以后的操作基本就没有难度的;所以说,学会分析一个类的内存模型,是每一个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引起。包括:

  • virtual function 机制 用以支持一个有效率的"执行期绑定"
  • 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。

image description

<strong>多重继承模型:</strong>

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

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

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

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

Paste_Image.png

<strong>虚拟继承模型:</strong>

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

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

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

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

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

Paste_Image.png

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

Paste_Image.png

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

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

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

原文地址:http://www.cnblogs.com/tracylee/archive/2012/12/18/2822431.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容