C++ 之多态(一)

什么是虚函数

  • 在类的定义中,前面有 virtual 关键字的成员函数称为虚函数;
  • virtual 关键字只用在类定义里的函数声明中,写函数体时不用。
class Base 
{virtual int Fun() ; // 虚函数
};int Base::Fun() // virtual 字段不用在函数体时定义
{ }

多态实现一

  • 「派生类的指针」可以赋给「基类指针」;
  • 通过基类指针调用基类和派生类中的同名「虚函数」时:
  1. 若该指针指向一个基类的对象,那么被调用是 基类的虚函数;
  2. 若该指针指向一个派生类的对象,那么被调用 的是派生类的虚函数。

这种机制就叫做“多态”,说白点就是调用哪个虚函数,取决于指针对象指向哪种类型的对象

// 基类
class CFather 
{
public:virtual void Fun() { } // 虚函数
};// 派生类
class CSon : public CFather 
{ 
public :virtual void Fun() { }
};int main() 
{CSon son;CFather *p = &son;p->Fun(); //调用哪个虚函数取决于 p 指向哪种类型的对象return 0;
}

多态实现二

  • 派生类的对象可以赋给基类「引用」
  • 通过基类引用调用基类和派生类中的同名「虚函数」时:
  1. 若该引用引用的是一个基类的对象,那么被调 用是基类的虚函数;
  2. 若该引用引用的是一个派生类的对象,那么被 调用的是派生类的虚函数。

这种机制也叫做“多态”,说白点就是调用哪个虚函数,取决于引用的对象是哪种类型的对象

// 基类
class CFather 
{
public:virtual void Fun() { } // 虚函数
};// 派生类
class CSon : public CFather 
{ 
public :virtual void Fun() { }
};int main() 
{CSon son;CFather &r = son;r.Fun(); //调用哪个虚函数取决于 r 引用哪种类型的对象return 0;
}
}

 示例一

class A 
{
public :virtual void Print() { cout << "A::Print"<<endl ; }
};// 继承A类
class B: public A 
{
public :virtual void Print() { cout << "B::Print" <<endl; }
};// 继承A类
class D: public A 
{
public:virtual void Print() { cout << "D::Print" << endl ; }
};// 继承B类
class E: public B 
{virtual void Print() { cout << "E::Print" << endl ; }
};

int main() 
{A a; B b; E e; D d;A * pa = &a; B * pb = &b;D * pd = &d; E * pe = &e;pa->Print();  // a.Print()被调用,输出:A::Printpa = pb;pa -> Print(); // b.Print()被调用,输出:B::Printpa = pd;pa -> Print(); // d.Print()被调用,输出:D::Printpa = pe;pa -> Print(); // e.Print()被调用,输出:E::Printreturn 0;
}

示例二

class Base 
{
public:void fun1() { fun2(); }virtual void fun2()  // 虚函数{ cout << "Base::fun2()" << endl; }
};class Derived : public Base 
{
public:virtual void fun2()  // 虚函数{ cout << "Derived:fun2()" << endl; }
};int main() 
{Derived d;Base * pBase = & d;pBase->fun1();return 0;
}

代码修改

class Base 
{
public:void fun1() { this->fun2();  // this是基类指针,fun2是虚函数,所以是多态}
}

总结 

这里代码迷惑人之处在于Derived 有Base的fun1接口,调用了fun1,不像平常的调用重写的虚方法。

this 指针的作用就是指向成员函数所作用的对象, 所以非静态成员函数中可以直接使用 this 来代表指向该函数作用的对象的指针。

pBase 指针对象指向的是派生类对象,派生类里没有 fun1 成员函数,所以就会调用基类的 fun1 成员函数,在Base::fun1() 成员函数体里执行 this->fun2() 时,实际上指向的是派生类对象的 fun2 成员函数。

因此,在非构造函数,非析构函数的成员函数中调用「虚函数」,就是多态实现!!!

另外,在构造函数和析构函数中调用「虚函数」,不是多态。编译时即可确定,调用的函数是自己的类或基类中定义的函数,不会等到运行时才决定调用自己的还是派生类的函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/136320.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL】一文学会所有MySQL基础知识以及基本面试题

文章目录 前言 目录 文章目录 前言 一、主流数据库以及如何登陆数据库 二、常用命令使用 三、SQL分类 3.1 存储引擎 四、创建数据库如何设置编码等问题 4.1操纵数据库 4.2操纵表 五、数据类型 六、表的约束 七、基本查询 八、函数 九、复合查询 十、表的内连和外连 十一、索引…

Gradle国内腾讯镜像

Gradle国内镜像 腾讯 https&#xff1a;//mirrors.cloud.tencent.com/gradle/ 使用方法&#xff1a;gradle不同版本下载太慢---腾讯做了国内镜像可以直接下载_gradle 下载-CSDN博客

Luatos Air700 改变BL0942串口波特率

LuatOs 改变模块串口波特率思路参照 luatos 改变AIR530串口波特率 BL0942默认串口波特率可以通过SCLK_BPS引脚接3.3V电源设置到9600bps 但如果调整到38400bps需要修改0x19寄存器 bl0942 v1.06版的特殊寄存器说明&#xff0c;注意早期版本特殊寄存器说明存在错误 完整代码 mai…

多路转接(上)——select

目录 一、select接口 1.认识select系统调用 2.对各个参数的认识 二、编写select服务器 1.两个工具类 2.网络套接字封装 3.服务器类编写 4.源文件编写 5.运行 一、select接口 1.认识select系统调用 int select(int nfds, fd_set readfds, fd_set writefds, fd_set ex…

【mmrotate】*** is not in the task util registry

问题&#xff1a; 使用mmrotate-1.x 自定义类时&#xff0c;明明已经注册&#xff0c;并添加到__init__.py中&#xff0c;但提示没有注册 from mmdet.registry import MODELSMODELS.register_module() class RotatedATSSAssigner(BaseAssigner): 分析&#xff1a; 具体看提…

在linux安装单机版hadoop-3.3.6

一、下载hadoop https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/core/hadoop-3.3.6/ 二、配置环境变量 1、配置java环境变量 2、配置hadoop环境变量 export HADOOP_HOME/usr/local/bigdata/hadoop-3.3.6 export HBASE_HOME/usr/local/bigdata/hbase-2.5.6 export JA…

Python进行数据可视化,探索和发现数据中的模式和趋势。

文章目录 前言第一步&#xff1a;导入必要的库第二步&#xff1a;加载数据第三步&#xff1a;创建基本图表第四步&#xff1a;添加更多细节第五步&#xff1a;使用Seaborn库创建更复杂的图表关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Pyth…

Vue 将响应式数据转为普通对象

toRaw&#xff1a;将一个 reactive 生成的响应式数据转为普通对象。 toRaw 适用于&#xff1a;获取响应式数据对应的普通对象&#xff0c;对这个普通对象所有的操作&#xff0c;都不会引起页面的更新。 markRaw&#xff1a;标记一个对象&#xff0c;使其永远不会再成为响应式…

设置区块链节点输出等级为警告级,并把日志存储阈值位100MB并验证;

题目 获取指定区块链节点输出等级为警告级&#xff0c;并设置日志存储阈值位100MB并验证&#xff1b; 操作步骤 1.切换目录 cd nodes/127.0.0.1/node0 2.打开配置文件并修改 vim config.ini warn&#xff1a;警告

NOIP2023模拟15联测36 均分财产

题目大意 有 n n n个数&#xff0c;你希望能删除其中不超过 k k k个数&#xff0c;然后将剩下的数划分为两个子集&#xff08;可以有重复的数字&#xff09;&#xff0c;满足这两个子集的数的和是相等的。 为了降低出题和做题的难度&#xff0c;可以认为这 n n n个数在 1 1 1…

初识微服务技术栈

认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构&#xff0c;这些架构之间有怎样的差别呢&#xff1f; 导学&#xff1a; 了解微服务的优缺点&#xff1b;了解微服务架构的演变过程&am…

智能井盖传感器功能,万宾科技产品介绍

在国家治理方面&#xff0c;对社会的治理是一个重要的领域&#xff0c;一定要在推进社会治理现代化过程中提高市政府的管理和工作能力&#xff0c;推动社会拥有稳定有序的发展。在管理过程中对全市井盖进行统一化管理&#xff0c;可能是市政府比较头疼的难题&#xff0c;如果想…

Mybatis(一)

1. Mybatis简介 MyBatis下载地址 1.1 MyBatis历史 MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下&#xff0c;iBatis3.x正式更名为MyBatis。代码于2013年11月迁移到Github…

Flink(三)【运行时架构】

前言 今天学习 Flink 的一些原理性的东西&#xff0c;比较偏概念&#xff0c;但是十分重要。有人觉得上来框框敲代码才能学到东西&#xff0c;那是狗屁不通的道理&#xff08;虽然我以前也这么认为&#xff09;。个人认为&#xff0c;学习 JavaEE那些框架&#xff0c;你上来就敲…

React 中的 Virtual DOM 是什么

在 React 中&#xff0c;Virtual DOM&#xff08;虚拟 DOM&#xff09;是一种用于提高性能和优化渲染的技术。它是 React 的核心概念之一。 Virtual DOM 是一个轻量级的内存数据结构&#xff0c;它是对真实 DOM 的抽象表示。在 React 中&#xff0c;每个组件都有对应的 Virtua…

毅速丨为什么不锈钢材料在金属3D打印中应用广泛

不锈钢材料作为一种常见材料&#xff0c;在金属3D打印中应用广泛&#xff0c;可以说是目前使用率最高的材料&#xff0c;为什么不锈钢大受欢迎&#xff0c;主要由几点原因。 第一、工艺适合性 金属3D打印的工艺&#xff0c;如直接金属激光烧结&#xff08;DMLS&#xff09;或选…

人工智能模型转ONNX 连接摄像头使用ONNX格式的模型进行推理

部署之后模型的运算基本上能快5倍。本地部署之后&#xff0c;联网都不需要&#xff0c;数据和隐私不像在网上那样容易泄露了。 模型部署的通用流程 各大厂商都有自己的推理工具。 训练的归训练&#xff0c;部署的归部署&#xff0c;人工智能也分训练端和部署端&#xff0c;每一…

Docker从入门到上天系列第四篇:docker平台入门图解与平台架构图解

大神推荐:作者有幸结识技术大神孙哥为好友获益匪浅,现在把孙哥作为朋友分享给大家。 孙哥链接:孙哥个人主页 作者简介:一个颜值99分,只比孙哥差一点的程序员。 本专栏简介:话不多说,让我们一起干翻Docker 本文章简介:话不多说,让我们讲清楚Docker的平台入门图解和平台…

达梦主备部署

达梦主备部署 一.概括1&#xff09;环境软件下载2&#xff09;集群规划 二.安装1&#xff09;安装前2&#xff09;安装数据库 三.主备机器部署1)初始化数据库&#xff08;1&#xff09;主库配置&#xff08;2&#xff09;备库配置 2)脱机备份&#xff08;1&#xff09;主服务器…