c++多态机制

多态

在 C++ 中,多态(Polymorphism)是一种面向对象编程的重要概念,它允许不同类的对象对同一消息做出不同的响应。具体来说,多态性允许基类的指针或引用在运行时指向派生类的对象,并且根据对象的实际类型来调用相应的成员函数。
多态性是通过虚函数来实现的。当一个基类的成员函数被声明为虚函数时,派生类可以通过覆盖(重写)这个函数来提供自己的实现。在运行时,调用这个虚函数的时候,实际上调用的是指向对象的实际类型的版本。
C++ 中的多态性有两种形式:静态多态(编译时多态)和动态多态(运行时多态)。
1.静态多态(编译时多态): 主要是通过函数重载和模板实现的,例如,同一个函数名可以有多个版本,根据参数的类型和数量来决定调用哪个版本的函数。这种多态性在编译时就已经确定了。
2.动态多态(运行时多态): 主要是通过虚函数和继承实现的,例如,基类指针指向派生类对象,并调用虚函数。在运行时,根据对象的实际类型来决定调用哪个版本的函数。这种多态性在运行时才会确定。

静态多态

静态多态(也称为编译时多态或早期多态)是指在编译时就确定函数调用的方式,主要通过函数重载和模板来实现。在静态多态中,编译器在编译时根据函数的签名(函数名称和参数列表)来确定调用哪个函数版本。
静态多态主要有两种形式:
1.函数重载: 函数重载允许在同一作用域内声明多个函数,它们具有相同的名称但参数列表不同。在调用函数时,编译器根据传递的参数的数量、类型和顺序来选择匹配的函数。

#include <iostream>// 函数重载示例
void print(int x) {std::cout << "Integer: " << x << std::endl;
}void print(double x) {std::cout << "Double: " << x << std::endl;
}int main() {print(5);       // 调用第一个 print 函数print(3.14);    // 调用第二个 print 函数return 0;
}

2.模板: 模板是一种通用编程技术,允许编写与特定类型无关的代码。通过使用模板,可以在不同类型的参数上执行相同的操作,而无需为每种类型编写不同的函数。

#include <iostream>// 模板示例
template <typename T>
void print(T x) {std::cout << "Value: " << x << std::endl;
}int main() {print(5);           // 实例化一个 int 类型的 print 函数print(3.14);        // 实例化一个 double 类型的 print 函数print("Hello");     // 实例化一个 const char* 类型的 print 函数return 0;
}

在这里插入图片描述

在静态多态中,函数调用的决定在编译时完成,因此性能更高。然而,静态多态的缺点是在编写代码时必须明确指定每个函数的具体版本,如果有大量的重载或模板,可能会导致代码量增加和可读性降低。

动态多态

动态多态(也称为运行时多态或晚期多态)是指在程序运行时根据对象的实际类型来决定调用哪个函数版本。动态多态性通过虚函数和继承来实现,在编译时无法确定函数调用的具体版本,而是在运行时根据对象的类型动态确定。
动态多态的实现需要满足以下两个条件:
1.基类中声明虚函数:在基类中将函数声明为虚函数,这样编译器就会在运行时进行函数调用的动态绑定。
2.派生类重写虚函数:派生类中可以通过重写(覆盖)基类中的虚函数来提供自己的实现。在调用这个虚函数时,会根据对象的实际类型来决定调用哪个版本的函数。
下面是一个简单的示例,演示了动态多态的用法:

#include <iostream>// 基类
class Animal {
public:// 虚函数virtual void makeSound() {std::cout << "Animal makes a sound" << std::endl;}
};// 派生类
class Dog : public Animal {
public:// 重写基类的虚函数void makeSound() override {std::cout << "Dog dog" << std::endl;}
};// 派生类
class Cat : public Animal {
public:// 重写基类的虚函数void makeSound() override {std::cout << "Cat cat" << std::endl;}
};int main() {// 创建派生类对象Dog dog;Cat cat;// 基类指针指向派生类对象Animal* ptr1 = &dog;Animal* ptr2 = &cat;// 通过基类指针调用虚函数,实现多态ptr1->makeSound(); // 调用的是派生类 Dog 的 makeSound() 函数ptr2->makeSound(); // 调用的是派生类 Cat 的 makeSound() 函数return 0;
}

Animal 类有一个虚函数 makeSound(),而 Dog 和 Cat 类分别继承自 Animal 类并重写了 makeSound() 函数。在 main() 函数中,我们创建了 Dog 和 Cat 类的对象,并将基类指针指向这些对象,然后通过基类指针调用虚函数 makeSound()。由于 makeSound() 是虚函数,所以在运行时根据对象的实际类型来决定调用哪个版本的函数,从而实现了动态多态性。

父类指针指向子类对象

在 C++ 中,可以使用父类的指针来指向子类的对象,这是实现多态的一种常见方式。这种行为被称为向上转型(upcasting),它允许您通过基类的接口来操作派生类的对象。这在面向对象编程中是非常有用的,因为它使代码更加灵活和可扩展。
下面是一个简单的示例说明了如何使用父类的指针来指向子类的对象:

#include <iostream>// 基类
class Base {
public:virtual void display() {std::cout << "Base class display() called" << std::endl;}
};// 派生类
class Derived : public Base {
public:void display() override {std::cout << "Derived class display() called" << std::endl;}
};int main() {// 创建派生类对象Derived derivedObj;// 使用基类指针指向派生类对象Base* basePtr = &derivedObj;// 通过基类指针调用虚函数,实现多态basePtr->display(); // 调用的是派生类的 display() 函数return 0;
}

Base 是基类,Derived 是派生类。Base 类有一个虚函数 display(),Derived 类重写了 display() 函数。在 main() 函数中,我们创建了 Derived 类的对象 derivedObj,然后使用 Base 类的指针 basePtr 指向了 derivedObj。最后,通过 basePtr 调用 display() 函数,由于 display() 函数是虚函数,所以调用的是 Derived 类中的版本,实现了多态行为。

方法调用

在 C++ 中,如果父类通过指针或引用调用一个虚函数,而这个虚函数在子类中被重写(override),那么调用的实际方法将取决于指针或引用所指向的对象的类型。这就是多态的体现。
具体来说,如果父类指针或引用指向的是子类对象,那么调用的方法将是子类中重写的版本;如果指针或引用指向的是父类对象,那么调用的方法将是父类中的版本。
下面是一个示例来说明这一点:

#include <iostream>// 基类
class Base {
public:virtual void show() {std::cout << "Base class show()" << std::endl;}
};// 派生类
class Derived : public Base {
public:void show() override {std::cout << "Derived class show()" << std::endl;}
};int main() {// 创建派生类对象Derived derivedObj;// 使用基类指针指向派生类对象Base* basePtr = &derivedObj;// 通过基类指针调用虚函数,实现多态basePtr->show(); // 调用的是派生类的 show() 函数return 0;
}

Base 类是基类,Derived 类是派生类。在 main() 函数中,我们创建了 Derived 类的对象 derivedObj,然后使用 Base 类的指针 basePtr 指向了 derivedObj。最后,通过 basePtr->show() 调用 show() 函数,由于 show() 是虚函数,因此调用的是 Derived 类中的版本,而不是 Base 类中的版本。

2024年5月11日21:04:05
疏影斜横水清浅,暗香浮动月黄昏。

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

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

相关文章

微信小程序支付全攻略:从零搭建到安全交易【微信支付】

微信小程序支付全攻略&#xff1a;从零搭建到安全交易 在移动互联网时代&#xff0c;微信小程序凭借其便捷性和高效性&#xff0c;成为了众多企业和开发者的心头好。其中&#xff0c;微信支付和小程序支付功能的集成&#xff0c;无疑是提升用户体验、增加商业转化的关键环节。…

1.5编程基础之循环控制 03:均值

描述 给出一组样本数据&#xff0c;计算其均值。 输入 输入有两行&#xff0c;第一行包含一个整数n&#xff08;n小于100&#xff09;&#xff0c;代表样本容量&#xff1b;第二行包含n个绝对值不超过1000的浮点数&#xff0c;代表各个样本数据。 输出 输出一行&#xff0…

CentOS 安装 Portainer

Portainer Community Edition是一个针对容器化应用程序的轻量级服务交付平台&#xff0c;可用于管理 Docker、Swarm、Kubernetes 和 ACI 环境。它的设计理念是部署和使用都简单&#xff0c;该应用程序允许您通过“智能”GUI 和/或广泛的 API 管理所有编排器资源。 1、查询Porta…

第七届精武杯部分wp

第一部分&#xff1a;计算机和手机取证 1.请综合分析计算机和手机检材&#xff0c;计算机最近一次登录的账户名是 答案&#xff1a;admin 创建虚拟机时直接给出了用户名 2. 请综合分析计算机和手机检材&#xff0c;计算机最近一次插入的USB存储设备串号是 答案&#xff1a…

抖音快速涨粉秘籍解密!从巨量千川投流真实粉丝,快速增粉1000~10万!

随着抖音的风靡&#xff0c;对于众多用户来说&#xff0c;快速涨粉已经成为了追求的目标。在这篇文章中&#xff0c;我们将揭秘全网都在搜索的抖音快速涨1000粉的方法&#xff0c;帮助你打造一个高人气的抖音账号&#xff01;从巨量千川投流到官方真实流量&#xff0c;再到真实…

外卖系统微信小程序支付

微信小程序支付时序图 其中第9.步骤就是微信小程序前端调用wx.requestPayment

QT7_视频知识点笔记_3_自定义控件,事件处理器⭐,定时器,QPainter,绘图设备,不规则窗口

第三天&#xff1a; 自定义控件&#xff0c;事件处理器⭐&#xff0c;定时器&#xff0c;QPainter,绘图设备&#xff0c;不规则窗口实现 1.自定义控件&#xff1a; 创建新的QT控件类&#xff0c;然后再需要使用的地方--》提升为 来使用如何使用基础控件的信号和槽函数&…

1.前端环境搭建

1.安装nodejs 因为我们开发Vue项目需要使用npm命令来创建和启动&#xff0c;安装node.js是为了获得这个命令&#xff0c;目前和使用node.js无关 下载地址&#xff1a;http://nodejs.cn/download/ 下载完之后安装&#xff0c;通过cmd查看是否安装成功 node --version2.创建项目…

FFmpeg提取视频参数,以及剪辑视频,拼接视频,合并视频,抽帧等

FFmpeg提取视频参数&#xff0c;以及剪辑视频&#xff0c;拼接视频&#xff0c;合并视频&#xff0c;抽帧等 视频封面图获取视频 视频封面图获取 #ifndef _BUFFER_CONTAINER_H_ #define _BUFFER_CONTAINER_H_ #include <Memory>template <typename T> class Buffer…

【力扣】1089.复写零

原题链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不…

深度探索Edge浏览器

深度探索Edge浏览器 随着网络技术的不断发展和人们对浏览体验要求的提高&#xff0c;浏览器作为我们日常上网的重要工具&#xff0c;其性能、安全性和易用性都成为了用户关注的重点。近年来&#xff0c;微软推出的Edge浏览器凭借其卓越的性能和独特的功能&#xff0c;逐渐成为…

探讨 vs2019 c++ 里函数指针与函数类型在使用上的语法区别

&#xff08;1&#xff09;咱们可以用 decltype &#xff08;&#xff09; 来判断函数的类型。但以这个类型定义有用的可指向已存在函数的变量&#xff0c;却行不通。测试如下&#xff1a; 如果把上面的注释去掉会报错&#xff1a; 所以函数类型只有语法意义。但在使用上没有函…

【C语言】/*操作符(下)*/

目录 一、操作符的分类 二、二进制和进制转换 2.1 进制 2.2 进制之间的转换 三、原码、反码、补码 四、单目操作符 五、逗号表达式 六、下标引用操作符[] 七、函数调用操作符() 八、结构体成员访问操作符 8.1 直接访问操作符(.) 8.2 间接访问操作符(->) 九、操作符…

openGauss学习笔记-280 openGauss性能调优-实际调优案例09-修改启动参数解决TPCC大幅度波动

文章目录 openGauss学习笔记-280 openGauss性能调优-实际调优案例09-修改启动参数解决TPCC大幅度波动280.1 现象描述280.2 优化分析openGauss学习笔记-280 openGauss性能调优-实际调优案例09-修改启动参数解决TPCC大幅度波动 280.1 现象描述 openGauss数据库在4路鲲鹏服务器单…

修改el-checkbox样式

一定要在最外层&#xff1b; //未选中框/deep/ .el-checkbox__inner{border-color: #0862a3;}//选中框/deep/ .el-checkbox__input.is-checked .el-checkbox__inner{background-color: #0862a3;border-color: #0862a3;}//未选中框时右侧文字/deep/ .el-checkbox__label{}//选中…

git 推送github 选https遇到登录 openSSH问题

使用https需要使用github令牌token作为密码&#xff0c; 使用SSH不需要登录。 还有一个问题&#xff1a; 创建github仓库后没有quick setup页面解决办法 千万不要点击任何多的操作&#xff01;&#xff01;&#xff01;输入仓库名&#xff0c;直接create&#xff01;&#x…

return语句

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 return语句 一、return语句后面跟表达式二、return无返回三、return返回的值和函数返回类型不一致四、return语句执行后,后方仍然存在代码五、存在分支语句&#xff0c;需考虑…

c++二分查找

左闭右闭 left 0; right numsize - 1; while(left<right) {middle (leftright)/2;if(nums[middle]>target){right middle-1;}else if(nums[middle]<target){left middle 1;}else return middle; } return -1; 左闭右开 left 0;right numsize; while(left&l…

去哪里找高清视频素材?推荐几个短视频素材免费网站

在数字时代&#xff0c;视频内容的质量直接影响观众的吸引力和留存率。尤其是高清、4K视频素材和可商用素材&#xff0c;它们在提升视觉质量和叙事深度方面起到了至关重要的作用。以下是一些国内外的顶级视频素材网站&#xff0c;它们提供的资源将为您的创作提供极大的支持和灵…

spring 创建bean的过程

spring 创建bean的过程 生成BeanDefinition – > 合并BeanDefinition --> 创建单例Bean对象(非懒加载) --> 依赖注入(属性赋值) --> 初始化前(PostConstruct)–>初始化(InitializingBean)–>初始化后(AOP)–>bean AbstractAutowireCapableBeanFactory.d…