1、多态对象有某种形式执行期类型判断法,多态其实就是使用一个基类指针寻址出一个派生类对象的意思。

2、识别一个class是否支持多态,唯一的方法就是看它是否有任何虚函数。

1)编译期,找到虚函数表,每个类对象被安插一个由编译器内部产生的指针,指向这个表格。每一个虚函数被指派一个表格索引值。

2)执行期,激活虚函数。

3、一个类只会有一个虚函数表,每一个表内含其对应的类对象激活虚函数的函数实例的地址,这些激活的虚函数包括:

1)这一个类所定义的函数实例,它会改写(overriding)一个可能存在的基类虚函数实例。

2)继承自基类的函数实例,这是在派生类中决定不改写虚函数时才会出现的情况。

3)一个pure_virtual_called()函数实例,它既可以扮演pure_virtual_function(纯虚函数)的空间保卫者角色,可以当做执行期异常处理函数。

4、当一个派生类继承自一个基类,一共有三种可能性:

1)它可以继承基类所声明的虚函数实例,准确说是,该函数实例的地址会被拷贝到派生类的虚函数表的相对应的位置。

2)它可以使用自己的函数实例,这表示它自己的函数实例地址必须放在对应的slot中。

3)他可以加入一个新的虚函数,这个时候虚函数表的尺寸会增大一个slot,而新的函数实例地址会被放进该solt中。

5、单一继承中,假设基类有一个函数x()在虚函数表的4位置,那么派生类的这个函数也是在4这个位置。

6、现在假设有一个基类指针,指向一个虚函数实例,如下:

ptr->z();

那么在编译期能够知道的东西是,经过ptr可以取到该对象的虚函数表,尽管你不知道ptr所指的真正对象。编译器可以知道每一个z函数在虚函数表中的位置,尽管不知道是哪一个z函数实例被调用。通过这些信息就可以把上面的代码转换成如下形式:

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

这一转化中,vptr表示编译器所安插的指针,指向虚函数表。4表示z函数被指派的slot号,唯一一个在执行期知道的东西是slot4所指的到底是哪一个z函数实例。

7、在单一继承模型中,虚函数机制十分良好,不但有效率而且很容易塑造出来模型,但是在多重继承和虚拟继承中对虚函数的支持就不那么美好了。

8、在多重继承中支持虚函数,其复杂度围绕着在第二个及后继的基类身上,以及必须在执行期调整this指针。

9、如下代码

class Base1{public:Base1();virtual ~Base1();virtual void speakClearly();virtual Base1 *clone() const;protected:float data_Base1;
};
class Base2{public:Base2();virtual ~Base2();virtual void mumble();virtual Base2 *clone() const;protected:float data_Base2;};class Derived:public Base1,public Base2{public:Derived();virtual ~Derived();virtual Derived *clone() const;protected:float data_Derived;
};

派生类支持虚函数的困难程度主要落在Base2对象身上,就上面的程序而言,有三个方面需要注意,1)虚析构函数。2)被继承下来的Base::mumble()函数 。3)一组clone函数实例。

//将一个派生类对象地址给基类指针
Base2 *pbase2= new Derived;//编译时期会产生以下代码
Derived *temp=new Derived;
Base2 *pbase2=temp ? temp++size(Aase1):0;

如果没有这样的调整,指针的任何非多态运用都会失败。

10、一般规则是,经由指向第二或后继之基类的指针或引用来调用派生类虚函数,其所连带的必要的this指针调整操作必须在执行期完成。也就是说,偏移量的大小,以及把偏移量加到this指针上头的一小段程序代码必须由编译器在某个地方插入。

11、thunk技术,就是一小段代码,用来1)用适当的offset值调整this指针。2)跳转到虚函数去。

12、在多重继承下,一个派生类内含n-1个额外的虚函数表,n表示上一层基类的个数,因此单一继承不会有额外的虚函数表。上面的例子,Derived会产生两个虚函数表,一个主要实例,与Base1(最左端基类)共享。一个次要实例,与Base2(第二个基类)有关。

13、针对每一个虚函数表,派生类对象中有对应的虚函数指针,虚函数指针会在构造函数中被设立初值。用以支持一个类拥有多个虚函数表的传统方法是将每一个表以外部对象的形式产生出来并给独一无二的名字。于是当你将一个派生类对象地址给一个Base1或Derived时,被处理的虚函数表是主要表格vtbl_Derived,而当你将一个Derived对象地址指定给一个Base2指针是,被处理的虚函数表是次要表格。

14、有三种情况,第二或后继的基类会影响对虚函数的支持。

1)通过一个指向第二个基类的指针,调用派生类虚函数。指向的次要表格。

Base2 *ptr=new Derived;
//调用Derived::~Derived()
//ptr必须向后调整sizeof(Base1)个byte
delete ptr;

2)通过一个指向派生类的指针调用第二个基类中继承来的虚函数,在此情况下派生类指针必须再次调整,指向第二个基类对象。指向主要表格。

Derived *pder=new Derived;
//调用Base2::mumble()
//pder必须向前调整sizeof(Base1)个byte
pder->mumble();

3)第三种情况发生在一个语言扩充性质下,允许一个虚函数的返回值类型有所变化,可能是基类类型,也可可能是公有的派生类类型,通过clone()函数可以来说明,clone函数的派生类版本传回一个派生类指针,改写了两个基类版本,当通过指向第二个基类的指针调用clone()时,this指针的offset问题就诞生了

Base2 *pb1=new Derived;
//调用Derived * Derived::clone()
//返回值必须调整。以指向Base2 对象
Base2 *pb2=pb1->clone;

当进行pb->clone()时,pb1会被调整指向Derived对象的起始地址,于是clone()的派生类版本会被调用,它会传回一个指针,指向一个新的派生类对象,该对象的地址被指定给pb2之前必须先经过调整,以指向Base2对象。

C++-----深度探索C++对象模型-第四章-Function语意学(二)相关推荐

  1. 深度探索C++对象模型第2章 构造函数语义学

    默认构造函数 两个误区: 1 任何class如果没有定义默认构造函数,就会被合成一个出来:只有在某些情况下被合成 2 编译器合成出来的默认构造函数会明确设定class中每一个数据成员的默认值 :默认值 ...

  2. 深度探索c++对象模型读书笔记:Data语意学-Data Member的绑定

    一个inline函数实体,在整个class声明未被完全看见之前,是不会被评估求值(evaluated)的,也就是说,对于如下代码: 1 extern int x; 2 3 class A 4 { 5 ...

  3. 第2章构造函数语义学读书笔记——深度探索c++对象模型

    深度探索c++对象模型 第2章 构造函数语义学 2.1 Default Constructor的构建操作 2.2 Copy Constructor的构造操作 2.3 程序转化语义学 2.4 成员的初始 ...

  4. 《深度探索C++对象模型(Inside The C++ Object Model )》学习笔记

    来源:http://dsqiu.iteye.com/blog/1669614 之前一直对C++内部的原理的完全空白,然后找到<Inside The C++ Object Model>这本书 ...

  5. [读书笔记]《深度探索C++对象模型》

    文章目录 前言 思维导图 第一章 关于对象 第二章 构造函数语意学 构造函数 拷贝构造函数 初始化列表 第三章 Data 语意学 第四章 Function 语意学 非静态成员函数 静态成员函数 虚成员 ...

  6. 《深度探索C++对象模型》读书笔记第五章:构造析构拷贝语意学

    <深度探索C++对象模型>读书笔记第五章:构造析构拷贝语意学 对于abstract base class(抽象基类),class中的data member应该被初始化,并且只在constr ...

  7. 深度探索C++ 对象模型(5)-Initialization list(1)

    以下四种情况,一定要使用成员初始化列表: 1.初始化一个引用成员 2.初始化一个const成员 示例代码为 class Shape{const int m_size; //const 常量int &a ...

  8. 《深度探索C++对象模型》--5 构造析构拷贝 6 执行期语意学

     <深度探索C++对象模型>--5构造.析构.拷贝语意学 1.纯虚函数: (1)C++可以定义和调用一个纯虚函数,不过只可以静态调用,不可以由虚拟机制调用. 注意:pure virtu ...

  9. 深度探索C++ 对象模型(7)-Data member的布局(虚继承)

    虚拟继承 namespace ObjectMultiDerived {class Point2d {public:// has virtual functionsvirtual void print( ...

最新文章

  1. case when 子查询_Oracle数据库-单表查询
  2. 10中文显示都是问号_CAD字体出现问号乱码的解决方法
  3. 【Extjs】 checkboxmodel 中事件处理
  4. Bioinfo:学习Python,做生信PartII 学习笔记
  5. 应该是最全的算法学习路线了吧法学习路线了吧
  6. PHP获取客户端ip的五种方式
  7. 删除Linux的用户
  8. Oracle 索引失效的六大限制条件
  9. one大白陪你聊聊2021年总结
  10. 金数据表单接口请求(php)
  11. 血压预测常用数据集整理
  12. linux simg2img,simg2img工具
  13. freecodecamp小练习——Falsy Bouncer过滤数组假值
  14. s3cmd 安装使用指南
  15. 五、嵌入式学习笔记--GPIO接口
  16. 骨传导蓝牙耳机哪个好,五款热门骨传导蓝牙耳机推荐
  17. 重启电脑数据丢失怎么恢复?这篇指南很受用!
  18. 轩辕谷,黄帝的诞生地
  19. Yii2 Using pretty URLs (Yii2 中使用漂亮的urls) from ----- Yii2 By Example
  20. 让opencv输出人脸检测的得分(置信率),找出一些和脸比较像但是不是脸的负样本

热门文章

  1. ArcGIS Pro免费试用申请与安装配置
  2. Modelsim 仿真 IP 核
  3. Java 类加载机制(二)
  4. 假设无线打印服务器,如何给我的usb接口的打印机改装成通过wifi连接的打印机...
  5. HTML之绝对定位Absolute
  6. BF(Best-first)算法
  7. android 7相机拍照功能介绍,镜头配备及拍照功能介绍_华为 Mate 7_手机Android频道-中关村在线...
  8. v-loam源码阅读(二)视觉里程计
  9. 15 11 汉明码matlab,数字通信汉明码报告
  10. 两个向量投影的计算公式推导