深度探索C++对象模型-第四章

说明:

​ <u>不是很清楚的点</u>,用下划线。

解答,用斜体;

重点,用粗体加粗;

第四章 Function 语意学

4.1 Member的各种调用方式

1. Nonstatic Member Functions

实际上编译器是将member function被内化为nonmember的形式,经过下面转化步骤:

  1. 给函数添加额外参数——this;
  2. 将对每一个nonstaitc data member的存取操作改为this指针来存取;
  3. 将member function 重写成一个外部函数。对函数名采用mangling 处理,使之成为独一无二的语汇;

2. Virtual Member Functions(虚成员函数)

ptr->f(); //f()为虚成员函数

内部转化为

(*ptr->vptr[1])(ptr);

其中:

  • vptr表示编译器产生的指针,指向virtual table。它被安插在每一个声明有(或继承自)一个或多个virtual functions 的class object 中。
  • 1 是virtual table slot的索引值,关联到normalize()函数。
  • 第二个ptr表示this指针。

3. Static Member Functions (静态成员函数)

Static Member Functions的主要特性就是它没有this指针

次要特性:

  • 不能被声明为const、volatile、virtual;
  • 不能够直接存取其class中的非静态数据成员;

Static Member Functions由于缺乏this指针,因此差不多等同于非成员函数

如果取一个static member function 的地址,获得的是其在内存的位置(也就是地址),而不是一个指向“class member function”的指针,如下:

&Point::count();

会得到一个数值,类型是:

unsigned int(*)();

而不是:

unsigned int(Point::*)();

4.2 Virtual Member Functions

C++中,多态表示以“一个public base class 的指针(或reference),寻址出一个derived class object”。

为了在执行期调用正确的虚函数,在编译时期:

  • 可以在每一个多态的class object身上增加两个members:
  1. 一个字符串或数字,表示class的类型;
  2. 一个指针vptr,指向某一个表格,表格中持有程序的虚函数们的执行期地址;
  • 每一个虚函数都被指派一个表格索引值;

那么,表格中的虚函数们地址如何被购建起来?

在C++中,虚函数们可经由其class object被调用,可以在编译时期获知。此外,这一组地址是固定不变的,执行期不可能新增或替换之。由于程序执行时,表格的大小和内容都不会改变,所以其建构和存取皆可以由编译器完全掌控。不需要执行期的任何介入。**

执行期要做的,只是在特定的虚函数表slot中激活虚函数。


每一个class 只会有一个virtual table,每一个table 含有对应的class object中所有active virtual functions 函数实体地址。这些active virtual function 包括:

  1. 这个class 所定义的函数实体(包括改写一个可能存在的base class virtual function函数实体)。
  2. 继承自base class 的函数实体(不被derived class改写)
  3. 一个pure_virtual_called()。

继承过程中,virtual table的三种可能性:

  1. 继承base class 所声明的virtual functions的函数实体。正确地说,是该函数实体的地址会被拷贝到derived class的virtual table相对应的slot之中。
  2. 使用自己的函数实体。这表示它自己的函数实体地址必须放在对应的slot之中。
  3. 可以加入一个新的virtual function。这时候virtual table 的尺寸会增大一个slot放进这个函数实体地址。

编译时期设定virtual function的调用:

ptr->z();

  • 一般而言,我并不知道ptr 所指对象的真正类型。然而可以经由ptr 可以存取到该对象的virtual table。
  • 虽然我不知道哪个Z()函数实体被调用,但知道每一个Z()函数地址都被放置某一个slot(如slot 4)的索引。

这样我们就可以将

ptr->z();

转化为:

(*ptr->vptr[4])(ptr);

唯一一个在执行期才能知道的东西是:slot4所指的到底是哪一个class object的z()函数实体。

多重继承下的 Virtual Functions

在多重继承中支持virtual functions,其复杂度围绕在第二个及其后面的base class 上,以及“必须在执行期调整this 指针”这一点。

一般规则是,经由指向“第二或后继base class 的指针”来调用derived class virtual function。调用操作连带的“必要的this指针调整”操作,必须在执行期完成。

在多重继承下,一个派生类内含n-1个额外的虚函数表,n表示其上一层基类的个数(因此,单一继承将不会有额外的虚函数表)。【若是双重继承,那么就会有一个与派生类共享的虚函数表

如下图:

4-2.png

【注】

  • base1的虚函数表是主要表格,base2的是次要表格;
  • 函数后面有加*,表示这不是真实的函数实例,是需要加this指针指向真正的函数实例。

4.3 函数的效能

non-member、static member或non-static member函数都被转换为完全相同形式,所以三者效率完全相同。

4.4 指向Member Function的指针

取一个non-static data member的地址,得到的结果是该member在class 布局中的bytes位置(再加1),所以它需要绑定于某个class object的地址上,才能够被存取。

取一个non-static member function的地址,如果该函数是non-virtual,则得到的是内存的真正地址,然后这个值也是不完全的,也需要绑定于某个class object的地址上,才能够调用函数。(所有的non-static member function都需要对象的地址,以参数this指出)

支持“指向Virtual Member Function”之指针

对于一个virtual function,其地址在编译时期是未知的,所能知道的仅是virtual function在其相关之virtual table的索引值,也就是说,对于一个virtual member function 取其地址,所能获得的只是一个索引值。

4.5 Inline Function

形参:

  • 传入参数,直接替换;
  • 传入常量,连替换都省了,直接变成常量;
  • 传入函数运行结果,则需要导入临时变量,以避免重复求值;

局部变量:

一般而言,inline函数中的每一个局部变量都必须被放在函数调用的一个封闭区段中,拥有一个独一无二的名称。

如果一次性调用N次,就会出现N个临时变量……程序的体积会暴增,如下:

minval = min( val1, val2 ) + min( foo(), foo()+1 );

因此要以分离的多个式子被调用。

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

推荐阅读更多精彩内容