f分布表完整图a=0.01_c++多态和虚函数表实现原理 - 一字千金
自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取:
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++多态和虚函数表实现原理 - 一字千金相关推荐
- f分布表完整图a=0.01_建筑电气工程图的一般规定
建筑工程图的格式与幅面尺寸 1.图纸格式 一张图纸的完整图面是由边框线.图框线.标题栏.会签栏等组成的,其格式如图1-1所示. 图1-1 图纸格式示例 (a)留装订边;(b)不留装订边 2.图纸幅面尺 ...
- f分布表完整图a=0.01_使用 Infer.NET 评价竞争对手
Infer.NET 是开放源代码的代码库,可用于创建概率性编程系统.我往往会将普通的计算机程序视作,主要基于有指定类型的值的变量(如有值"Q"的 char 变量).概率性编程主要基 ...
- f分布表完整图a=0.05_MySQL8.0新特性-invisible indexes
作者 李春·沃趣科技首席架构师 出品 沃趣科技 作者简介: 曾就职于阿里巴巴,全程参与阿里数据架构从Oracle迁移到MySQL过程,参与分布式中间件Cobar设计. | 导语 MySQL 8.0版本 ...
- f分布表完整图a=0.05_2019年05月16日,沪深A股股票分析
纽约华尔街,伦敦金融城,Tier 1投行,我们希望撕掉标签,用数据说话. 欢迎您留言和赞赏,谢谢.一.整体分析 我们选取了沪深A股的股票,利用历史数据对超过60种交易策略进行了预测回测. 下表中列出了 ...
- f分布表完整图a=0.01_自动控制原理2.2.2传递函数零极点,零点如何影响输出响应曲线...
2.传递函数零点和极点 传递函数分子多项式和分母多项式经因式分解后可写为如下形式: Zi是分子多项式零点,称为传递函数零点,Pj是分母多项式零点,称为传递函数极点.系数K*=b0/a0称为传递函数系数 ...
- f分布表完整图a=0.01_SQL Server从入门到精通——学习笔记01(数据库基础知识篇)...
1.1 数据库的概念 数据库(DataBase,DB):是存放数据的仓库,只不过这些数据存在一定的关联,并按一定的格式存放在计算机上. 1.2 数据库管理系统 数据库管理系统(DataBase Man ...
- f分布表完整图_【教育统计答疑】如何理解正态分布、均值分布、^2分布、t分布和F分布...
许多教育统计的初学者都表示这几个分布感到学起来非常吃力,结合最近上课的体会以及答疑的情况,觉得很有必要在这里简单地对这部分内容进行澄清和梳理,以助理解. 首先,"为什么要学习这几个分布&qu ...
- f分布表完整图_分布式计算引擎之星——Spark
点击上方"数风云"关注我们吧 文/李萌 Spark作为分布式计算引擎的一颗璀璨之星,继承了MapReduce分布式并行计算的优点,并改进了MapReduce明显的缺陷.它使用一种面 ...
- f分布表完整图_标准正态分布函数数值表怎么查?(加完整分布函数表)
最近在整理数据时,忽然想到数理统计的其中一种分布,相信作为质量人一定不陌生,我们常常提到数据的分布是否服从正态分布,这是对一组连续数据分布一种描述,还会涉及到如何检验正态分布,对于这个分布的来龙去脉和 ...
- 如何利用EXCEL生成任意自由度任意显著因子的F分布表
1.Excel软件中的FINV()函数.当已知自由度,求某累计概率所对应的F值时,可以使用Excel软件中的FINV()函数.有了此函数,即可省去查F分布表的麻烦.该函数的语法格式为:FINV(Pro ...
最新文章
- 斯坦福全球AI报告:人才需求两年暴增35倍,中国机器人部署量涨500%
- 快来看看Google出品的Protocol Buffer,别仅仅会用Json和XML了
- java 服务器线程池测试
- simulink学习笔记(2)
- Ecology 建模表单 数据库字段与页面字段对应关系显示
- 博客园在我的博客添加点击小心心特效
- Parcelbale接口
- SpringBoot之json转java实体类
- android 代码操作.db demo,Android实现商品展示效果
- Postman 汉化包(设置中文)
- 登记车架号/VIN码用车架号识别
- 独立开发者能够从这位作家身上学些什么
- 服务器选云主机还是VPS主机呢?
- 基于JavaWeb的果蔬生鲜交易系统
- 爬取虎扑社区-晒晒照片
- [LifeHack]Hack决策系统
- 如何解决Mathtype在Word中功能区是灰色的情况
- 计算机里没有机械硬盘分区,电脑不显示机械硬盘怎么办 几个步骤轻松搞定
- Three.js_解决谍影锯齿闪烁重影模型的方法
- 波音 777 飞机由 Ada 语言驱动