深度探索C++面对对象模型第四章笔记

概要

member的各种调用方式:

1.Nonstatic Member Functions

  1. C++的设计准则之一即为nonstatic member function与non member function有着相同的效率.
  2. 这里还谈到了name mangling 这个编译器里的一个实现,因为要达到上面设计准则的要求,需要对名字进行一些改变来应对C++中类以及函数重载等要求,因此如果你看到了一些奇怪的名字,那估计就是这个原因了~~

2.Virtual Member Functions

  1. 虚函数的调用方法:(*ptr->vptr[slot])(ptr);这个比较好理解吧,需要注意的是slot是固定不变的,当子类有新的方法时会加在后面,这个后面会有详细讲解.
  2. 注意区分多态调用(通过指针),以及普通的调用方式的区别,里面有个很有意思的关于编译器优化的例子,可以看看

3.Static Member Functions

a.书中说这个是最后才被加进来的特性,因此讲述了在上古时代大家是怎么使用这种方法的. b. 特性: 1)不能直接存取nonstatic members:很好理解,这货在类存在之前就存在了肯定无法操作了 2)不能够被声明为const volatile virtual 3)不需经由class object才被调用 c.我在实现算法时,把类封装好后,会把demo声明为static函数,然后把一些实验的逻辑写进去,最后直接在main函数里调用这个demo就ok,这样可以省去在main里写一堆东西,最后搞糊涂了~个人之言希望有更好的想法~


重点!!

Virtual Member Functions

这部分还跟往常一样,要和“三巨头”见面了,首先是简单的单一继承,然后就是麻烦的多重继承,虚拟继承了.最后一部分是实验部分,大家有兴趣可以试一试~

1. 单一继承

  1. 在说起这些实现前,首先我们先回顾下历史: 1.虚拟机制是什么? 2.编译器应当怎么做才能支持呢? 作者先给出了多态的定义:以一个public base class的指针(或reference),寻址出一个derived class object. 后面提出了消极多态以及积极多态这两个概念,这里我有点疑惑,我的理解是一个是编译时期,另一个是在真正使用时。

  2. 那么问题来了,我们如何实现支持诸如 ptr->z()这样调用呢?首先列出支持它所需要的信息及支持方案:
    1): ptr所指对象的真实类型:提供一个字符串或数字,表示其类型 2)z()的真实位置:一个指针,指向某个表格 vptr
    可以看到,表格在这里面占有者重要的地位,那么表格的信息应当在编译时期就应该确定了,以后也不应该变化了,所以上面说slot是不会变的,这个表格也就是虚函数表,指向这个表格的指针就是所谓的vptr了。 那么聪明的你思考一下,这个表格里会遇到几种情况呢,下面我们列出来瞧瞧~: 1) 一个正常的虚函数 = = 2) 继承自父类,被overriding了,那么这个函数就不一样了~ 3) pure virtual function ..你敢调用我?分分钟异常给你看~ 4) 新的虚拟成员来了~ 书中说了,这个还可以当一个空间保卫者的角色,关于这个我有点疑惑~求解释
    了解了以上情况后,很容易就明白了单一继承会遇到的问题,对于 1),则直接复制父类的定义, 2).3)替换成自己的. 4) 加到最后

可以看到,单一继承是多么的美好,简单,并且也不会出现一些奇怪的歧义问题……那么...接下来的事情就没有那么美好了。

2.多重继承

还记得上一章的多重继承吗?为了找第二个及以后类的成员,我们需要提供足够的位移信息,把this移来移去,对于成员函数,也是这样,我们也要移来移去(可怜的this指针...)

同上一章一样,多重继承的难度全部都落在了第二个及以后的class上,例如: {base2 pbase2 = new derived; } 可以看到,这是一个普通的多态形式,好,如果你认为我就简单的和单一继承(单一继承只有一个vptr,子类仅仅就是比父类大,新来的就加到最后就可以了,但是多重继承没有那么简单,有着不同的几个类,虚拟继承就更...了,他们需要共享一些数据,每次派生的时候还不一样..需要提供额外的信息了)一样,指向新申请内存的开头呗……好那么,如果用户要这样调用呢:
pbase2->somemember. 这是一个非多态调用,要访问一个成员...注意你现在指针指向的是base1..那么好了。。调用失败..所以上述new时,一般是这样的: derived
temp = new derived; *
pbase2 = temp?temp+sizeof(base1):0;//这里加上了0值防御。 问题又来了:我要调用destructor了..这时候你总不能还指向desturctor吧。。又要调整回去了。。
可以想象,运行时期这种情况会不断的出现,因此我们迫切的需要一些信息来支持,最早Bjarne是把virtual table加大,增加一些offset信息,这样会使其他不需要offset的函数连坐,直到thunk技术拯救了他们,这个技术我也只从书上了解过,利用一小段汇编来调整this指针,然后跳到正确的virtual function上去。 上面信息的问题解决了,我们就是要处理表格的问题了:C++将表格分为:
1)主要表格:与最左端的base1 object共享,这个表格记录了所有的虚函数,并且也记录了那个函数应当调整this指针
2)剩下的都是次要的表格:记录了每个子类自己的虚函数,并且将一些全局的虚函数,例如clone,destructor之类的进行改写,同时也记录了offset指针(为什么只需记录自己的呢,因为你在使用p_base2进行多态调用的时候,肯定只能知道base2中有什么函数了,否则编译会通不过的~)。 关于上面的解释,大家可以认真的看看p165的那张图,非常清晰,同时可以看到主要表格中base1中的slot也是严格不变的细节。

1)书中还提到了SUN一个项目细节,将主要表格与次要表格连起来,以提高连接器的效率 2) 同时还有一个细节需要注意,例如clone函数执行时,我们是通过pbase2调用的,那么他返回的应当指向pbase2,需要进行调整,因此通过不同的指针进行多态调用,函数也是有些略微不同...太。。。了..因此书中提到了split function 这个技术...

3.虚拟继承

嗯……大师也有说服的时刻。。表示关于虚拟继承的讨论,简直像进了迷宫一样..他有着一整柜的答案……大师给的建议:不要再一个virtual base class 里声明 nonstatic data members...多谢不讨论这部分。。给我们省了不少书费233333333


后记以及无责任的吐槽..

关于深度探索C++面对对象模型的笔记就到此为止了,在这之前C++的发展与演化,这两本书前前后后看了不少遍,从最早的觉得啊这是什么东西……到现在没事的时候就会翻翻重温一下经典,真心觉得每个语言的发展背后,都有无数的人贡献出了他们的智慧,要好好的吸取~~

最近github 好像被攻击了...大家应该知道是谁干的吧..这两天 push 代码时,根本就连不上,今天 git pages 好像也挂了,我的博客也阵亡了。。真是一阵伤感,希望能快点恢复……嗯,最近闲的时候在看shadowsocks的源码,准备研究研究,搞个黑科技来玩玩……顺便说说python真是赞……

开题答辩完了有了大把时间码代码,改了不知道多少遍以后自己的实验代码的框架总算有个雏形了,后面继续安安静静的写吧~



Previous     Next
SureD /
Published under (CC) BY-NC-SA in categories c++  tagged with C++ 
分享到: 更多
>