自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取:

https://www.cnblogs.com/bclshuai/p/11380657.html

C++多态以及虚函数表实现原理

目录

1      定义

2      虚函数表实现原理

3      实例解析

定义父类

父类对象地址空间剖析

子类继承父类的虚函数表

3.     单继承覆盖和不覆盖对比

3.     子类继承多个父类

.3     多层继承的子类

1        定义

C++中的虚函数的作用主要是实现了多态的机制。关于多态,子类对象赋值给父类指针,然后通过父类的指针调用实际子类覆盖父类的虚函数实现。赋值不同的子类对象给父类指针,可以使用父类指针调用不同子类的虚函数(必须是覆盖父类的函数),这种技术可以让父类的指针有“多种形态”。

2        虚函数表实现原理

每个子类对象创建时,会有一个虚函数表,而且虚函数表在对象首地址开始,以达到高效访问的目的。一个子类继承多个父类时,子类对象的头部有多个虚函数表,把父类的虚函数表复制过来,按照继承顺序排列。如果子类覆盖了父类的虚函数,则替换掉复制过来的父类虚函数表中对应位置的虚函数。子类中的自定义虚函数,在第一个虚函数表中,排在父类虚函数后面(主流说法是这样,但是实际测试,并没有)。当用子类的对象赋值给父类指针时,父类指针指向了子类虚函数表,当调用函数时,就会从子类虚函数表中查找函数,去调用子类覆盖父类的虚函数,这样就实现了多态。

3        实例解析

定义父类

class Base {

public:

virtual void f() { cout << "Base::f" << endl; }

virtual void g() { cout << "Base::g" << endl; }

virtual void h() { cout << "Base::h" << endl; }

int a=0;

};

父类对象地址空间剖析

创建一个对象Base b;

父类的虚函数表示意图为

虚函数表在对象地址首部,函数指针按照定义的顺序在虚函数表中,可以通过地址访问的方式去访问这些函数。

int main()

{

typedef void(*Fun)(void);

Base b;

cout << "虚函数表地址:" << (int*)(&b) << endl;

cout << "1" << *(int*)(&b) << endl;

cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl;

Fun funf = ((Fun)*((int*)*(int*)(&b) + 0));

Fun fung= ((Fun)*((int*)*(int*)(&b) + 1));

Fun funh= ((Fun)*((int*)*(int*)(&b) + 2));

funf();

fung();

funh();

system("pause");

return 0;

}

输出结果

b地址空间如下图所示:

理解下面一句是怎么获取到函数地址的。

pFun = (Fun)*((int*)*(int*)(&b));

(&b)获取到对象b的地址。

(int*)(&b))转化为int*的指针,对象b的前4个字节是虚函数表的地址,int* 也是四个字节,这种强制转换,是把&a开始的4个字节当作一个整体,也就是虚函数表的地址,虚函数表地址在对象地址空间首部。

*(int*)(&b))  *虚函数表地址,得到的是虚函数表的内存空间,虚函数表内存空间首部是虚函数f的地址,即Base::f()的地址。

((int*)*(int*)(&b))在转换为int*类型的指针,就得到了四个字节的虚函数f的地址。f,g,h的地址各占四个字节,int*的指针+1,就是向后移动四个字节,得到g函数的地址,+2,就是再向后移动四个字节,得到h函数的地址。

*((int*)*(int*)(&b))  *虚函数地址,得到的是虚函数f的实际的存储空间。

(Fun)*((int*)*(int*)(&b));转换为函数指针。

思考:如果虚函数fgh是private私有的,那么通过这种方式仍然可以获取到私有函数的地址fgh,并且去访问这些私有函数。

子类继承父类的虚函数表

3.         单继承覆盖和不覆盖对比

class Derver: public Base{

public:

virtual void f1() { cout << "Derver::f" << endl; }

virtual void g1() { cout << "Derver::g" << endl; }

virtual void h1() { cout << "Derver::h" << endl; }

};

查看无覆盖和有覆盖继承的情况,右边子类覆盖了父类的f函数。

无覆盖的子类对象地址空间。网上说父类虚函数在虚表前面,子类虚函数在后面

但是实际情况是虚函数表中只有父类虚函数,如下所示

有覆盖的子类对象地址空间,子类虚函数表的首位替换了子类覆盖的函数

虚函数表中是子类虚函数替换了父类虚函数的位置,也没有未覆盖的子类虚函数f1和g1。

总结:单继承的子类对象虚函数表中,只包含父类对象的虚函数和覆盖的子类虚函数,子类虚函数会替换掉对应位置的父类虚函数。子类自定义的虚函数不在虚函数表中。

3.         子类继承多个父类

(1)   定义一个子类继承三个基类,继承关系如下图

代码实现

class Base1 {

public:

virtual void f() { cout << "Base1::f" << endl; }

virtual void g() { cout << "Base1::g" << endl; }

virtual void h() { cout << "Base1::h" << endl; }

};

class Base2 {

public:

virtual void f() { cout << "Base2::f" << endl; }

virtual void g() { cout << "Base2::g" << endl; }

virtual void h() { cout << "Base2::h" << endl; }

};

class Base3 {

public:

virtual void f() { cout << "Base3::f" << endl; }

virtual void g() { cout << "Base3::g" << endl; }

virtual void h() { cout << "Base3::h" << endl; }

};

class Mult :public Base1, public Base2,public Base3 {

public:

virtual void f() { cout << "Mult::f" << endl; }

virtual void g1() { cout << "Mult::g" << endl; }

};

class Grander :public Derver

{

public:

virtual void f1() { cout << "Grander::f" << endl; }

virtual void g1() { cout << "Grander::g1" << endl; }

};

(2)   查看子类对象的地址空间

如下图所示,子类对象空间有三个基类虚表,子类覆盖的函数f替换了虚表中对应的位置。子类自有的虚函数网上说是在第一个虚表后面。但是实际却没有。

如下图所示,是实际的地址空间,第一个虚表中并没有看到子类的虚函数g1.

总结:子类继承多个父类,子类对象中包含了三个父类的虚函数表,按照继承顺序排列。子类覆盖的虚函数会替换对应位置的三个父类虚函数。子类自定义的虚函数也不在虚函数表中。

.3         多层继承的子类

子类Derver继承父类Base,然后Grander类继承Derver类。

代码实现如下

class Base {

private:

virtual void f() { cout << "Base::f" << endl; }

virtual void g() { cout << "Base::g" << endl; }

virtual void h() { cout << "Base::h" << endl; }

int a = 0;

};

class Derver: public Base{

public:

virtual void f() { cout << "Derver::f" << endl; }

virtual void g1() { cout << "Derver::g1" << endl; }

virtual void h1() { cout << "Derver::h1" << endl; }

int d =1;

};

class Grander :public Derver

{

public:

virtual void f() { cout << "Grander::f" << endl; }

virtual void g1() { cout << "Grander::g1" << endl; }

};

内存虚表结构如下所示,只虚表中只有有Base类中函数Base::g(),Base::h(),还有覆盖的子类函数Grander::f()。其他的函数都没有。连覆盖Derver的Grander::g1()都没有。这是什么鬼?

总结:多层继承,子类对象的虚函数表中值包含Base类的虚函数,子类覆盖的虚函数替换掉对应位置的Base类虚函数。中间的Derver虚函数和Grander中自定义的虚函数不存在虚函数表中。

(1)基类Base指针指向对象Derver

Base* pB = new Derver();

得到的内存结构如下图所示

有两个虚拟表,虚函数表中地址相同,函数是基类的虚函数和Derver覆盖基类的虚函数。

(2)中间的指针Derver*指向孙类对象Grander

得到的虚表结构如下,虚函数是基类base虚函数和Grander覆盖基类的虚函数Grander::f();

Derver* pD  = new Grander();

(3)基类Base指针指向孙类对象Grander

得到的虚函数表如下图所示

Base* pDG = new Grander();

总结:多层继承时,虚函数表中保存的是基类的虚函数Base和覆盖基类的虚函数。虚函数表会保留继承层级关系。会有两个虚函数表,表中的函数地址相同。

f分布表完整图a=0.01_c++多态和虚函数表实现原理 - 一字千金相关推荐

  1. f分布表完整图a=0.01_建筑电气工程图的一般规定

    建筑工程图的格式与幅面尺寸 1.图纸格式 一张图纸的完整图面是由边框线.图框线.标题栏.会签栏等组成的,其格式如图1-1所示. 图1-1 图纸格式示例 (a)留装订边;(b)不留装订边 2.图纸幅面尺 ...

  2. f分布表完整图a=0.01_使用 Infer.NET 评价竞争对手

    Infer.NET 是开放源代码的代码库,可用于创建概率性编程系统.我往往会将普通的计算机程序视作,主要基于有指定类型的值的变量(如有值"Q"的 char 变量).概率性编程主要基 ...

  3. f分布表完整图a=0.05_MySQL8.0新特性-invisible indexes

    作者 李春·沃趣科技首席架构师 出品 沃趣科技 作者简介: 曾就职于阿里巴巴,全程参与阿里数据架构从Oracle迁移到MySQL过程,参与分布式中间件Cobar设计. | 导语 MySQL 8.0版本 ...

  4. f分布表完整图a=0.05_2019年05月16日,沪深A股股票分析

    纽约华尔街,伦敦金融城,Tier 1投行,我们希望撕掉标签,用数据说话. 欢迎您留言和赞赏,谢谢.一.整体分析 我们选取了沪深A股的股票,利用历史数据对超过60种交易策略进行了预测回测. 下表中列出了 ...

  5. f分布表完整图a=0.01_自动控制原理2.2.2传递函数零极点,零点如何影响输出响应曲线...

    2.传递函数零点和极点 传递函数分子多项式和分母多项式经因式分解后可写为如下形式: Zi是分子多项式零点,称为传递函数零点,Pj是分母多项式零点,称为传递函数极点.系数K*=b0/a0称为传递函数系数 ...

  6. f分布表完整图a=0.01_SQL Server从入门到精通——学习笔记01(数据库基础知识篇)...

    1.1 数据库的概念 数据库(DataBase,DB):是存放数据的仓库,只不过这些数据存在一定的关联,并按一定的格式存放在计算机上. 1.2 数据库管理系统 数据库管理系统(DataBase Man ...

  7. f分布表完整图_【教育统计答疑】如何理解正态分布、均值分布、^2分布、t分布和F分布...

    许多教育统计的初学者都表示这几个分布感到学起来非常吃力,结合最近上课的体会以及答疑的情况,觉得很有必要在这里简单地对这部分内容进行澄清和梳理,以助理解. 首先,"为什么要学习这几个分布&qu ...

  8. f分布表完整图_分布式计算引擎之星——Spark

    点击上方"数风云"关注我们吧 文/李萌 Spark作为分布式计算引擎的一颗璀璨之星,继承了MapReduce分布式并行计算的优点,并改进了MapReduce明显的缺陷.它使用一种面 ...

  9. f分布表完整图_标准正态分布函数数值表怎么查?(加完整分布函数表)

    最近在整理数据时,忽然想到数理统计的其中一种分布,相信作为质量人一定不陌生,我们常常提到数据的分布是否服从正态分布,这是对一组连续数据分布一种描述,还会涉及到如何检验正态分布,对于这个分布的来龙去脉和 ...

  10. 如何利用EXCEL生成任意自由度任意显著因子的F分布表

    1.Excel软件中的FINV()函数.当已知自由度,求某累计概率所对应的F值时,可以使用Excel软件中的FINV()函数.有了此函数,即可省去查F分布表的麻烦.该函数的语法格式为:FINV(Pro ...

最新文章

  1. 斯坦福全球AI报告:人才需求两年暴增35倍,中国机器人部署量涨500%
  2. 快来看看Google出品的Protocol Buffer,别仅仅会用Json和XML了
  3. java 服务器线程池测试
  4. simulink学习笔记(2)
  5. Ecology 建模表单 数据库字段与页面字段对应关系显示
  6. 博客园在我的博客添加点击小心心特效
  7. Parcelbale接口
  8. SpringBoot之json转java实体类
  9. android 代码操作.db demo,Android实现商品展示效果
  10. Postman 汉化包(设置中文)
  11. 登记车架号/VIN码用车架号识别
  12. 独立开发者能够从这位作家身上学些什么
  13. 服务器选云主机还是VPS主机呢?
  14. 基于JavaWeb的果蔬生鲜交易系统
  15. 爬取虎扑社区-晒晒照片
  16. [LifeHack]Hack决策系统
  17. 如何解决Mathtype在Word中功能区是灰色的情况
  18. 计算机里没有机械硬盘分区,电脑不显示机械硬盘怎么办 几个步骤轻松搞定
  19. Three.js_解决谍影锯齿闪烁重影模型的方法
  20. 波音 777 飞机由 Ada 语言驱动

热门文章

  1. 小程序 界面响应速度优化
  2. 进制转换--2进制转16进制
  3. 终极 Shell on-zshrc
  4. 视频基本原理 -视频接口之 - MIPI接口(五)
  5. 永洪科技怎么样_「永洪科技」北京永洪商智科技有限公司怎么样? - 职友集
  6. Python:实现pigeon sort鸽巢算法(附完整源码)
  7. PDF文件中的图片导出
  8. 详解:字符转换函数(大写转小写,小写转大写)
  9. 怎样清理xp系统垃圾
  10. ChatGPT 会开源吗?