<四>虚函数 静态绑定 动态绑定
代码1
class Base
{
public:
Base(int data=10):ma(data){
cout<<"Base()"<<endl;
}
void show(){cout<<"Base Show()"<<endl;}
void show(int){cout<<"Base Show(int)"<<endl;}
~Base(){cout<<"~Base()"<<endl;}
protected:
int ma;
};
class Derive : public Base
{
public:
Derive(int data=20):Base(data),mb(data){
cout<<"Derive()"<<endl;
}
void show(){cout<<"Derive Show()"<<endl;}
~Derive(){cout<<"~Derive()"<<endl;}
private:
int mb;
};
int main(){
Derive d(20);
Base *pb=&d;
pb->show(); //静态绑定(编译期间绑定)
pb->show(100) //静态绑定(编译期间绑定)
cout<<sizeof(Base)<<endl; // 4 字节
cout<<sizeof(Derive)<<endl; // 8字节
cout<<typeid(pb).name()<<endl; // clas Base *
cout<<typeid(*pb).name()<<endl; // class Base
return 0;
}
代码2
class Base
{
public:
Base(int data=10):ma(data){
cout<<"Base()"<<endl;
}
//虚函数
virtual void show(){cout<<"Base Show()"<<endl;}
//虚函数
virtual void show(int){cout<<"Base Show(int)"<<endl;}
~Base(){cout<<"~Base()"<<endl;}
protected:
int ma;
};
class Derive : public Base
{
public:
Derive(int data=20):Base(data),mb(data){
cout<<"Derive()"<<endl;
}
void show(){cout<<"Derive Show()"<<endl;}
~Derive(){cout<<"~Derive()"<<endl;}
private:
int mb;
};
int main(){
Derive d(20);
Base *pb=&d;
pb->show(); //动态绑定(运行期间绑定)
pb->show(100) //动态绑定(运行期间绑定) )
cout<<sizeof(Base)<<endl; // 12 字节
cout<<sizeof(Derive)<<endl; // 16 字节
cout<<typeid(pb).name()<<endl; //
cout<<typeid(*pb).name()<<endl; //
return 0;
}
//在上面的代码中,如果一个类中定义了虚函数,编译器会做什么??
//1:一个类里面定义了虚函数,那么编译阶段,编译器给这个类会产生一个唯一的vftable虚函数表,
// 虚函数表中主要存储的内容就是RTTI和虚函数地址,如下图
//2:当程序运行时,每一张(程序中的可能有很多类都有虚函数,每一个类都会对应一个虚函数表)虚函数表都会加载到内存的.rodata区
// 一个类里面定义了虚函数,那么这个类定义的对象,其运行时,在内存中开始部分,多存储一个vfptr虚函数指针,指向相应
// 类型的虚函数表vftable, 一个类型定义的n个对象,指向同一张表
//3:一个类里面虚函数的个数,不影响对象内存大小(vfptr),影响的是虚函数表的大小
//4:如果派生类中的方法,和基类继承来的某个方法,返回值,函数名,参数列表都相同,而且基类的方法是virtual虚函数
// 那么派生类的这个方法,自动处理成虚函数


在上面代码2中,Base 中void show()和 void show(int) 为虚函数, 在Derive 中有返回值,函数名,参数列表都
相同的 show()方法,这个时候 我叫 重写(或覆盖 即要返回值,函数名,参数列表 都相同),这个Derive中的void show()方法也会处理成虚函数.所以有
下图 Derive中的show()方法地址替换掉继承来的Base的show()函数地址 ,同时我们也可以看到Base中的 void show(int) 并没有被覆盖

覆盖:基类和派生类的方法,返回值,函数名以及参数列表都相同,而且基类的方法是虚函数,那么派生类的方法就自动处理成虚函数,他们之前成为覆盖关系.
所以根据上图,我们说 覆盖 其实是指虚函数表中函数地址的覆盖
代码2中的这段代码
Base *pb=&d;
pb->show(); //动态绑定(运行期间绑定)
pb->show(100) //动态绑定(运行期间绑定) )
pb->show() pb是Base类型,所以编译器会去Base中查看void show()函数情况
如果是普通函数,那么静态绑定(编译期绑定),但是发现是 void show()函数是个虚函数就进行动态绑定了
同理 pb->show(100)发现Base中的void show(int )也是个虚函数,所以执行动态绑定(运行期绑定).
但是 这两个函数在Derive虚函数表中的区别就是,void show()被Derive覆盖掉了,即虚函数表中的地址被覆盖了
而void show(int) 为被覆盖,所以虚函数表中的 地址仍然是Base的void show(int)的地址
----------------------------------------
cout<<sizeof(Base)<<endl; // 4 +8 =12 字节 Base中又多了一个虚函数表指针
cout<<sizeof(Derive)<<endl; // 8+8 =16 字节 Derive 多了一个虚函数表指针
------------------------------------------------------
cout<<typeid(pb).name()<<endl; // Base *
cout<<typeid(*pb).name()<<endl; //
关于这句代码typeid(*pb).name(),即打印指针指向对象的类型, 先看pb是Base类型,再看有没有虚函数
1:如果没有虚函数,那么*pb 识别的是编译时期的类型,即 Base class
2:如果有虚函数,那么 *pb 识别的是运行时的类型,即RTTI类型,RTTI是存储在虚函数表中,所以要在运行期识别
即 pb->d(vfptr)->Derive vftable -> Class Derive

<四>虚函数 静态绑定 动态绑定的更多相关文章
- C++中虚函数的动态绑定和多态性
目录 静态类型 vs 动态类型.静态绑定 vs 动态绑定 虚函数动态绑定实现机制.虚析构函数 多态性 一.静态 vs 动态 静态类型 VS 动态类型.静态类型指的是对象声明的类型,在编译器确定的.动态 ...
- C++入门经典-例8.7-多态,利用虚函数实现动态绑定
1:多态性是面向对象程序设计的一个重要特征,利用多态性可以设计和实现一个易于扩展的系统.在C++语言中,多态是指具有不同功能的函数可以用同一个函数名,这样就可以用一个函数名调用不同内容的函数,发出同样 ...
- C++之易混淆知识点四---虚函数与虚继承
C++面向对象中,虚函数与虚继承是两个完全不同的概念. 一.虚函数 C++程序中只要类中含有虚拟函数,编译程序都会为此类生成一个对应的虚拟函数跳转表(vtbl),该虚拟函数跳转表是一个又若干个虚拟函数 ...
- 【转】深入理解C++的动态绑定和静态绑定 & 不要重定义虚函数中的默认参数
为了支持c++的多态性,才用了动态绑定和静态绑定.理解他们的区别有助于更好的理解多态性,以及在编程的过程中避免犯错误.需要理解四个名词:1.对象的静态类型:对象在声明时采用的类型.是在编译期确定的.2 ...
- C++中的动态类型与动态绑定、虚函数、运行时多态的实现
动态类型与静态类型 静态类型 是指不需要考虑表达式的执行期语义,仅分析程序文本而决定的表达式类型.静态类型仅依赖于包含表达式的程序文本的形式,而在程序运行时不会改变.通俗的讲,就是上下文无关,在编译时 ...
- 从零开始学C++之虚函数与多态(一):虚函数表指针、虚析构函数、object slicing与虚函数
一.多态 多态性是面向对象程序设计的重要特征之一. 多态性是指发出同样的消息被不同类型的对象接收时有可能导致完全不同的行为. 多态的实现: 函数重载 运算符重载 模板 虚函数 (1).静态绑定与动态绑 ...
- C++多态性----运算符重载与虚函数
一.多态性 ①概述:多态是指同样的消息被不同类型的对象接收时导致的不同行为. ②类型: 可以分为四类:重载多态.强制多态.包含多态.参数多态. ------------------------ --- ...
- 【C++】多态性(函数重载与虚函数)
多态性就是同一符号或名字在不同情况下具有不同解释的现象.多态性有两种表现形式: 编译时多态性:同一对象收到相同的消息却产生不同的函数调用,一般通过函数重载来实现,在编译时就实现了绑定,属于静态绑定. ...
- C++对象内存模型2 (虚函数,虚指针,虚函数表)
从例子入手,考察如下带有虚函数的类的对象内存模型: class A { public: virtual void vfunc1(); virtual void vfunc2(); void func1 ...
- 读书笔记 effective c++ Item 36 永远不要重新定义继承而来的非虚函数
1. 为什么不要重新定义继承而来的非虚函数——实际论证 假设我告诉你一个类D public继承类B,在类B中定义了一个public成员函数mf.Mf的参数和返回类型并不重要,所以假设它们都是void. ...
随机推荐
- [机器学习]-分类问题常用评价指标、混淆矩阵及ROC曲线绘制方法
分类问题 分类问题是人工智能领域中最常见的一类问题之一,掌握合适的评价指标,对模型进行恰当的评价,是至关重要的. 同样地,分割问题是像素级别的分类,除了mAcc.mIoU之外,也可以采用分类问题的一些 ...
- 利用高级组策略管理AGPM复制组策略GPO
有时候管理多个林,在一个林中配置了GPO之后,想复制出来用到其它林里.默认系统的组策略管理里没有这个功能.但是微软在微软企业桌面优化套件Microsoft Desktop Optimization P ...
- 使用脚本在FTP上传、下载文件
由于最近勒索病毒变种又一次爆发,公司内部封锁了TCP 445端口.导致原来通过文件共享的方式上传下载的计划任务无法执行.所以,我开设了FTP服务器来完成这个工作. 关于如何建立FTP服务器,请看这里 ...
- 8.云原生之Docker容器镜像构建最佳实践浅析
转载自:https://www.bilibili.com/read/cv15220861/?from=readlist 本章目录 0x02 Docker 镜像构建最佳实践浅析 1.Dockerfile ...
- Kubernetes生态架构图
图片来源于:https://gitbook.curiouser.top/ 一.kubernetes 集群架构图 二.Openshift or Kubernetes 集群架构图 三.常见的 CI/CD ...
- Kibana仪表盘(Dashboard)详解
Kibana 仪表板(Dashboard) 展示保存的可视化结果集合. 在编辑模式下,您可以根据需要安排和调整可视化结果集,并保存仪表板,以便重新加载和共享. 创建一个仪表板 如何创建一个仪表板: 点 ...
- Elastic:Elastic Maps 基于位置的警报 - 7.10
文章转载自:https://elasticstack.blog.csdn.net/article/details/112535618
- 《吐血整理》高级系列教程-吃透Fiddler抓包教程(26)-Fiddler如何抓取Android7.0以上的Https包-上篇
1.简介 众所周知,假如设备是android 7.0+的系统同时应用设置targetSdkVersion >= 24的话,那么应用默认是不信任安装的Fiddler用户证书的,所以你就没法抓到应用 ...
- 面向制造企业普适性ERP、MES类产品为什么那么难找?
标准化与个性化之间的矛盾怎么可能通过普适性的ERP.MES系统来解决?为什么难?就跟你找一套适合所有人穿的衣服一样难,事实上这个比找衣服更难!人与人之间高矮胖瘦各不相同.肤色体型各有差异,把同一套衣服 ...
- 详解商业智能“前世今生”,“嵌入式BI”到底是如何产生的?
嵌入式分析是使任何应用程序或用户更容易获得数据分析和商业智能的技术. 商业智能是通过分析业务数据辅助决策获取数据背后的 0信息. 商业智能软件和技术包含了报表查询,OLAP,数据挖掘及高级数据分析,最 ...