《深度探索C++对象模型》第四章 Function语意学
member function相对于nonmember function之间不存在效率之间的差别,因为编译器内部已经将“member 函数实体”转化为对等的“nonmember 函数实体”,转化过程:
1.改写函数的函数原型,以安插一个额外的参数到member function中,用于提供一个存储管道,使class object得以调用该函数,该额外参数被称为this指针。
2.将每一个“对nonstatic data member的存取操作”改为经由this指针来存取
3.将成员函数重新写成一个外部函数,对函数名称进行“mangling”处理,使它在程序中成为独一无二的词汇。
名字的特殊处理(name mangling)
一般而言,member的名字前会被加上class 的名称,形成独一无二的命名,例如:
Class Bar{public: int val;}
class Foo:public Bar{public int val;}
//Foo 的内部
class Foo
{
public :
int ival_3bar;
int ival_3foo;
}
不管要处理哪一个ival,都可以通过“name mangling”,都可以绝对清楚地指出来,由于member functions可以被重载化(overloaded),所以需要更广泛的mangling手法,以提供绝对独一无二的名称。
Virtual Member Funtion(虚成员函数)
如果normalize()是一个virtual member function,那么
ptr->normalize();
//将会被内部转化为下面这样
(*ptr->vptr[1])(ptr);
1.vptr表示由编译器产生的指针,指向virtual table,它被安插在每一个“声明有或继承自一个或多个virtual functions”的class object中,事实上其名称也会“mangled”,因为在一个复杂的class派生体系中,可能会存在多个vptrs。
2.1是virtual table slot的索引值,关联到normailize()函数
3.第二个ptr表示this指针。
为了支持virtual function机制,必须首先能够对多态对象有某种形式的“执行器类型判断法”,在C++中,多态表示“以一个public base class 指针(或reference)寻址出一个derived class object”的意思。
多态又可分为passive(消极)和active(积极)
Point*ptr=new Point2d;
ptr=new Point3d;//这是消极的
ptr的多态机能主要扮演一个传送机制的角色,经由它,我们可以在程序的任何地方采用一组public derived类型,这种多态形式被称为是passive的,可以在编译期完成(virtual base class除外)
当被指出的对象真正被使用时,多态也就变成了active的了,下面对于virtual function的调用
ptr->z();//active的多态
其中z()是一个virtual function,那么什么信息才能让我们在执行期调用正确的z()实体?我们要知道:
1.ptr所指对象的真实类型,这可使我们选择正确的z()实体。
2.z()实体位置,以便我们能够调用它。
在实现上,可以在每一个多态的class object身上添加两个members
1.一个字符串或者数字,表示class 的类型。
2.一个指针,指向某表格,表格中带有程序的virtual functions的执行期地址。
表格中的virutual functions地址如何被构建的?
在编译时期(由上面的ptr=new Point3d可知)就可以获得virtual function的地址,此外,这一组地址是固定不变的,执行期不可能新增或替换之,由于程序执行时,表格的大小和内容都不会发生改变,所以其构建和存取都可以由编译器完全掌握,不需要执行器的任何接入。
上面是准备好地址,接下来是如何寻址:
1.为了找到表格,每一个class object被安插上一个由编译器内部产生的指针,指向该表格。
2.为了找到函数地址,每一个virutual function被指派一个表格索引值。
执行期要做的,只是在特定的记录着virutual function的地址激活virutal function
一个class只会有一个virtual table,每一个table内涵其对应的class object中所有的active virtual functions函数实体的地址,这些active virtual function包括:
1.这个class 所定义的函数实体,它会改写(overriging)一个可能存在的base class virtual function函数实体。
2.继承自base class的函数实体,这是在derived class决定不该写virtual function时才会出现的情况。
3.一个pure_virtual_called()函数的实体。
每一个virtual function都派有一个固定的索引值,这个索引值在整个继承体系中与特定的virtual function相关联。
当B继承自A的时候:
1.它可以继承base class所声明的virutal functions的函数实体,正确的说,是该函数实体的地址会被拷贝到派生类的virtual table相对应的slot中
2.它可以使用自己的函数实体,这表示它自己的函数实体地址必须放在对应的slot中。
3.它还可以加入一个新的virtual function。这时候virtual table的尺寸会增大一个slot,而新的函数实体地址也会放进该slot中。
如果我有这样一个函数调用:
ptr->z();
那么我怎么拥有足够多的只是在编译时期设定virtual function调用呢?
1.一般而言,我们不知道ptr所指对象的真正类型,但是我们可以知道,经由ptr可以存取到该对象的virtual table;
2.虽然我们不知道哪一个z()会被调用,但我知道每一个z()函数的地址都被放在slot4中,这样我们就可以转化为:
(*ptr->vptr[4])(ptr);
以上只包含单继承
多继承下的虚函数
(图太难画了,我直接截书里的图吧)
在多重继承下,一个派生类内涵n个virtual table,n是上一层base classes的数目,针对每一个virtual tables,derived对象中有对应的vptr。
《深度探索C++对象模型》第四章 Function语意学的更多相关文章
- 深度探索C++对象模型第四章:函数语义学
C++有三种类型的成员函数:static/nonstatic/virtual 一.成员的各种调用方式 C with class 只支持非静态成员函数(Nonstatic member function ...
- 《深度探索C++对象模型》第二章 | 构造函数语意学
默认构造函数的构建操作 默认构造函数在需要的时候被编译器合成出来.这里"在需要的时候"指的是编译器需要的时候. 带有默认构造函数的成员对象 如果一个类没有任何构造函数,但是它包含一 ...
- Android深度探索-卷1第四章心得体会
这一章的和三章的git用法有联系,so,吧上一章的git基本用法搞好了再来,具体的方法就是看书上网查,这里就不做详细步骤介绍了.这章就有点意思了,是源码的下载和编译,有能看的,能自己鼓捣的,本章介绍的 ...
- 深度探索C++对象模型之第一章:关于对象之C++对象模型
一.C和C++对比: C语言的Point3d: 数据成员定义在结构体之内,存在一组各个以功能为导向的函数中,共同处理外部的数据. typedef struct point3d { float x; f ...
- 深度探索C++对象模型之第一章:关于对象之对象的差异
一.三种程序设计范式: C++程序设计模型支持三种程序设计范式(programming paradiams). 程序模型(procedural model) char boy[] = "cc ...
- 深度探索C++对象模型之第二章:构造函数语意学之Copy constructor的构造操作
C++ Standard将copy constructor分为trivial 和nontrivial两种:只有nontrivial的实例才会被合成于程序之中.决定一个copy constructor是 ...
- 深度探索C++对象模型之第二章:构造函数语意学之Default constructor的构造操作
C++新手一般由两个常见的误解: 如果任何class没有定义默认构造函数(default constructor),编译器就会合成一个来. 编译器合成的的default constructor会显示的 ...
- 【C++对象模型】第四章 Function 语意学
1.Member的各种调用方式 1.1 Nonstatic Member Functions 实际上编译器是将member function被内化为nonmember的形式,经过下面转化步骤: 1.给 ...
- 深度探索C++对象模型之第二章:构造函数语意学之成员初始值列表
当我们需要设置class member的初值时,要么是经过member initialization list ,要么在construcotr内. 一.先讨论必须使用member initializa ...
随机推荐
- NVIDIA Isaac Gym安装与使用
NVIDIA做的Isaac Gym,个人理解就是一个类似于openai的Gym,不过把环境的模拟这个部分扔到了GPU上进行,这样可以提升RL训练的速度. 官网:https://developer.nv ...
- JavaScript基础&实战(5)js中的数组、forEach遍历、Date对象、Math、String对象
文章目录 1.工厂方法创建对象 1.1 代码块 1.2.测试结果 2.原型对象 2.1 代码 2.2 测试结果 3.toString 3.1 代码 3.2 测试结果 4.数组 4.1 代码 5.字面量 ...
- 动词时态=>1.动作的时间和状态
时态 什么是时态? 英语的时态,是由动作的时间 + 动作的状态:这俩一起构成了时态 动词的时间和状态在一起,合称时态 理论上的十六种时态 先将 时间和状态的概念搞清楚,再具体讨论,用什么词,去构成时态 ...
- Audacity开源音频处理软件使用入门
操作系统 :Windows10_x64 Audacity版本:3.2.1 Audacity是一款开源.免费.跨平台的音频处理及录音软件,支持Windows.macOS及Linux操作系统. 这里记录下 ...
- AgileBoot - 如何集成内置数据库H2和内置Redis
本项目地址: github: https://github.com/valarchie/AgileBoot-Back-End gitee: https://gitee.com/valarchie/Ag ...
- visual studio插件开发-Menu
工欲善其事,必先利其器,作为程序员我们很大部分时间在和ide打交道,好的插件可以大大提高我们的编程效率,我开发过几个vs插件来解决一键生成dbmodels,快速部署到服务器,总结下来最关键的还是对于M ...
- TKK: 更新 TKK 失败,请检查网络连接 idea翻译错误-IDEA翻译失败-Translation用不了
IDEA 提示:更新 TKK 失败,请检查网络连接 解决方法: 1.进入 C:\Windows\System32\drivers\etc 找到 hosts文件修改 注意:如果用记事本打开不能修改,则修 ...
- 5.django-模型ORM
Django中内嵌了ORM框架,不需要直接编写SQL语句进行数据库的操作,通过定义模型类来完成对数据库中表的操作 O:Object,也就是类对象的意思 R:Relation,关系数据库中表的意思 M: ...
- AI绘画提示词创作指南:DALL·E 2、Midjourney和 Stable Diffusion最全大比拼 ⛵
作者:韩信子@ShowMeAI 深度学习实战系列:https://www.showmeai.tech/tutorials/42 自然语言处理实战系列:https://www.showmeai.tech ...
- 关于 risrqnis
这道题里最有用的( Range Insert Subset Range Query [n?] In Set 破案了 我那五个点是因为维护不知道有什么用的东西炸了 删了就过了 题面 [JRKSJ R4] ...