C++的面向对象学习(8):面向对象编程的三大特性之:多态

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 一、多态是什么?
    • 多态是面向对象编程中的一个重要概念,指的是同一个函数在不同的对象上具有不同的行为。具体来说,多态是通过虚函数实现的。
  • 二、多态的种类:静态多态和动态多态
    • ①静态多态:如函数重载与运算符重载
    • ②动态多态:派生类与虚函数
      • 语法:基类对该多态函数用virtual声明。
  • 三、函数重写与函数重载的区别
  • 四、通过基类的指针或引用来访问派生类对象(重要)
  • 五、多态与虚函数的内部实现原理
  • 六、多态有什么用?应用场合?
  • 七、纯虚函数和抽象类
    • 1.在多态中,父类的虚函数实现是没有意义的,调用的主要是子类中重写的内容,所以父类虚函数可改写为纯虚函数。
    • 2.只要一个类里有了纯虚函数,这个类就是抽象类了。抽象类无法被实例化对象。
    • 3.子类必须重写抽象类的纯虚函数,否则也属于抽象类。


一、多态是什么?

多态是面向对象编程中的一个重要概念,指的是同一个函数在不同的对象上具有不同的行为。具体来说,多态是通过虚函数实现的。

二、多态的种类:静态多态和动态多态

①静态多态:如函数重载与运算符重载

静态多态是指在编译时就确定了函数的调用方式,也称为编译时多态。C++中的函数重载就是一种静态多态,编译器在编译时就根据函数参数的类型和数量来确定调用哪个函数。

②动态多态:派生类与虚函数

动态多态是指在运行时根据对象的类型来确定函数的调用方式,也称为运行时多态。C++中的虚函数就是一种动态多态,当通过基类指针或引用调用虚函数时,实际上会根据指针或引用所指向的对象类型来调用相应的函数实现。

语法:基类对该多态函数用virtual声明。

三、函数重写与函数重载的区别

函数重写(override)和函数重载(overload)是两种不同的概念。

函数重载是指在同一个作用域内,可以定义多个同名函数,但是它们的参数列表不同。编译器会根据调用时提供的参数类型和数量,自动匹配合适的函数进行调用。函数重载可以提高代码的可读性和可维护性,但是需要注意避免过度使用,以免造成混淆。

函数重写是指在派生类中重新定义基类中已有的虚函数,使得派生类对象在调用该函数时,会优先调用派生类中的函数,而不是基类中的函数。函数重写可以实现运行时多态,提高代码的灵活性和可扩展性。

class animal {
public:virtual void print() {cout << "hello world" << endl;}
};class cat :public animal {
public:void print() {//重写基类的成员函数cout << "hello world cat" << endl;}void print(int n) {//重载成员函数for (int i = 0; i < n; i++) {cout << "hello world cat" << endl;}}
};int main() {animal a;cat cat1;a.print(); // 输出 "hello world"cat1.print(); // 输出 "hello world cat"cat1.print(3); // 输出三次 "hello world cat"return 0;
}

四、通过基类的指针或引用来访问派生类对象(重要)

多态需要通过基类的指针或引用来访问派生类对象。通过将派生类对象赋值给基类指针或引用,可以实现对派生类对象的统一访问

什么意思呢?就是说基类会有很多个派生类,我不想通过一个个实例化派生类的对象来调用其各自的函数,而是想直接通过基类来统一的管理与调用。

class animal {
public:virtual void sound() {cout << "animal sound" << endl;}
};class cat :public animal {
public:void sound() {cout << "meow" << endl;}
};class dog :public animal {
public:void sound() {cout << "woof" << endl;}
};int main() {animal* animals[3];animals[0] = new animal();animals[1] = new cat();animals[2] = new dog();for (int i = 0; i < 3; i++) {animals[i]->sound();}return 0;
}

mian函数是核心,我直接建立了一个类animal类型的指针数组,指针0指向类animal,指针1和2分别指向类cat与dog。这样的话,才能保证不同指针调用的是不同类的多态函数。如果不加virtual修饰,则三个指针都会调用基类函数。

五、多态与虚函数的内部实现原理

多态的实现依赖于虚函数的内部实现原理。在面向对象编程中,虚函数是通过虚函数表(vtable)和虚函数指针(vptr)来实现多态的。

虚函数表是一个存储了虚函数地址的表格,每个包含虚函数的类都有一个对应的虚函数表。虚函数表中的每个条目都指向相应虚函数的地址。当一个类被定义为包含虚函数时,编译器会在该类的对象中插入一个隐藏的指针,称为虚函数指针(vptr)。虚函数指针指向该类的虚函数表。

当通过基类指针或引用调用虚函数时,编译器会使用虚函数指针来查找虚函数表,并根据对象的实际类型找到对应的虚函数地址进行调用。这样就实现了在运行时根据对象的实际类型来确定调用的函数,从而实现了多态。

六、多态有什么用?应用场合?

我举一个例子:
实际工作中,需要开发一个计算器的项目,如果我只定义一个计数器类,在该类里面写函数,可以使用多态来处理不同类型的数据对象。
开发中的原则上:要求修改是闭合的,拓展是开放的。
所以,对于一个基类,最好只是声明一个大纲,而正式的各种不同功能的实现,需要通过多态,在派生类中完成。

#include <iostream>// 基类 Calculator
class Calculator {
public:virtual double calculate(double num1, double num2) {return 0;
}
};// 加法计算器类
class AddCalculator : public Calculator {
public:double calculate(double num1, double num2)  {return num1 + num2;}
};// 减法计算器类
class SubCalculator : public Calculator {
public:double calculate(double num1, double num2) {return num1 - num2;}
};int main() {// 创建加法计算器对象Calculator* addCalc = new AddCalculator();double result1 = addCalc->calculate(5.0, 3.0);std::cout << "加法计算结果: " << result1 << std::endl;// 创建减法计算器对象Calculator* subCalc = new SubCalculator();double result2 = subCalc->calculate(5.0, 3.0);std::cout << "减法计算结果: " << result2 << std::endl;delete addCalc;delete subCalc;return 0;
}

我如果后续想对加法、减法进行修改或者拓展,就可以完全不管其他乘或除部分的代码,只负责这一个派生类即可。可以通过多态的方式,统一地操作不同类型的计算器对象,可读性更强了。

七、纯虚函数和抽象类

1.在多态中,父类的虚函数实现是没有意义的,调用的主要是子类中重写的内容,所以父类虚函数可改写为纯虚函数。

纯虚函数是在基类中声明但没有实现的虚函数。它的声明形式为在函数声明后面加上= 0。纯虚函数没有函数体,因此派生类必须实现它们才能被实例化。
例:

// 抽象类 Shape
class Shape {
public:virtual double getArea() const = 0; // 纯虚函数virtual double getPerimeter() const = 0; // 纯虚函数
};

2.只要一个类里有了纯虚函数,这个类就是抽象类了。抽象类无法被实例化对象。

3.子类必须重写抽象类的纯虚函数,否则也属于抽象类。

// 派生类 Circle
class Circle : public Shape {
private:double radius;public:Circle(double r) : radius(r) {}double getArea() const override {return 3.14 * radius * radius;}double getPerimeter() const override {return 2 * 3.14 * radius;}
};// 派生类 Rectangle
class Rectangle : public Shape {
private:double length;double width;public:Rectangle(double l, double w) : length(l), width(w) {}double getArea() const override {return length * width;}double getPerimeter() const override {return 2 * (length + width);}
};

主程序:

int main() {Circle circle(5.0);Rectangle rectangle(4.0, 6.0);std::cout << "圆的面积: " << circle.getArea() << std::endl;std::cout << "圆的周长: " << circle.getPerimeter() << std::endl;std::cout << "矩形的面积: " << rectangle.getArea() << std::endl;std::cout << "矩形的周长: " << rectangle.getPerimeter() << std::endl;return 0;
}

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

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

相关文章

微服务(6)

目录 26.LoadBalanced注解的作用&#xff1f; 27.什么是断路器&#xff1f; 28.什么是Hystrix? 29.什么是Feign? 30.SpringCloud有几种调用接口方式&#xff1f; 26.LoadBalanced注解的作用&#xff1f; 开启客户端负载均衡 27.什么是断路器&#xff1f; 当一个服务调用…

【eclipse】eclipse开发springboot项目使用入门

下载eclipse Eclipse downloads - Select a mirror | The Eclipse Foundation 安装eclipse 其他一步一步即可 我们是开发java web选择如下 界面修改 Window->Preferences-> 修改eclipse风格主题 Window->Preferences->General->Appearance 修改字体和大小…

【用pandas,写入内容到excel工作表的问题】

用pandas的话&#xff08;如下面代码所示&#xff09;&#xff0c;写入内容到excel工作表&#xff0c;有几个问题&#xff1a; 1、运行的之前&#xff0c;excel需要先关闭。 2、如果Sheet2存在&#xff0c;那么就会报错。如果if_sheet_exists‘replace’&#xff0c;那么就会把…

基于 CefSharp 实现一个文件小工具

I’m not saying you can’t be financially successful I’m saying have a greater purpose in life well beyond the pursuit of financial success Your soul is screaming for you to answer your true calling You can change today if you redefine what success is to …

Python和Java的优缺点

Python的优点&#xff1a; 简单易学&#xff1a;Python的语法简洁清晰&#xff0c;易于学习和理解。丰富的库和框架&#xff1a;Python拥有庞大的标准库和活跃的开源社区&#xff0c;可以快速使用各种功能强大的库和框架&#xff0c;比如NumPy、Pandas、Django等。可读性强&am…

深度强化学习DQN训练避障

目录 一.前言 二.代码 2.1完整代码 2.2运行环境 2.3动作空间 2.4奖励函数 2.5状态输入 2.6实验结果 一.前言 深度Q网络&#xff08;DQN&#xff09;是深度强化学习领域的一项革命性技术&#xff0c;它成功地将深度学习的强大感知能力与强化学习的决策能力相结合。在过…

VIM8 文本实战学习

目录 第一章 开始Vim 之旅 1.1 模式界面与无模式界面对比 1.2 通过.vimrc文件来配置Vim 1.3 Vim 交换文件 1.4 通过:help阅读Vim手册 本章小结 第二章 高级编辑和文本浏览 主要内容&#xff1a; 2.1 安装插件 2.2 组织工作区 2.2.1 缓冲区 2.2.2 插件——unimpaire…

Kafka集群详解

Kafka介绍Kafka集群介绍Kafka集群特点Kafka集群搭建在这里插入图片描述Kafka集群如何进行故障切换Kafka集群Leader的选举Kafka集群如何快速横向拓展Kafka集群搭建最佳实践Kafka集群可以使用单节点Zookeeper吗Kafka集群的消费者信息保存在那里Kafka集群的Topic的分区数的设置规则…

YOLOv8改进 添加可变形注意力机制DAttention

一、Deformable Attention Transformer论文 论文地址&#xff1a;arxiv.org/pdf/2201.00520.pdf 二、Deformable Attention Transformer注意力结构 Deformable Attention Transformer包含可变形注意力机制&#xff0c;允许模型根据输入的内容动态调整注意力权重。在传统的Tra…

鸿蒙 Window 环境的搭建

鸿蒙操作系统是国内自研的新一代的智能终端操作系统&#xff0c;支持多种终端设备部署&#xff0c;能够适配不同类别的硬件资源和功能需求。是一款面向万物互联的全场景分布式操作系统。 下载、安装与配置 DevEco Studio支持Windows系统和macOS系统 Windows系统配置华为官方推…

Fine-Tuning Language Models from Human Preferences

Abstract 奖励学习(reward learning)可以将强化学习(RL)应用到由人类判断定义奖励的任务中,通过询问人类问题来构建奖励模型。奖励学习的大部分工作使用了模拟环境,但是关于价值的复杂信息经常是以自然语言的形式表达的。我们相信语言奖励学习是使强化学习在现实世界任务…

小程序面试题 | 17.精选小程序面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Nmap使用

Nmap 文章目录 Nmap端口扫描及其原理端口扫描用法Zenmap配置说明 Nmap 是一款开源免费的网络发现&#xff08;Network Discovery&#xff09;和安全审计&#xff08;Security Auditing&#xff09;工具官网为&#xff1a;www.nmap.org。 一般情况下&#xff0c;Nmap用于列举网…

从0开始界面设计师 Qt Designer

QT程序界面的 一个个窗口、控件&#xff0c;就是像上面那样用相应的代码创建出来的。 但是&#xff0c;把你的脑海里的界面&#xff0c;用代码直接写出来&#xff0c;是有些困难的。 很多时候&#xff0c;运行时呈现的样子&#xff0c;不是我们要的。我们经常还要修改代码调整界…

day12--java高级编程:网络通讯

5 Day19–网络通信(Socket通信) 说明&#xff1a; io流是跟本地的文件进行数据的传输&#xff0c;读或者写。网络通信&#xff1a;数据在网络中进行的传输。 本章专题与脉络 1. 网络编程概述 Java是 Internet 上的语言&#xff0c;它从语言级上提供了对网络应用程序的支持&…

Maven项目提示Ignored pom.xml问题

1 环境 &#xff08;1&#xff09;IDEA开发工具&#xff1a;2022.2.1 &#xff08;2&#xff09;JDK&#xff1a;Java17&#xff08;Spring6要求JDK最低版本是Java17&#xff09; &#xff08;3&#xff09;Spring&#xff1a;6.1.2 &#xff08;4&#xff09;Maven 3.8.8 2 …

准确!!ClickHouse同步MySQL详细步骤

1.安装配置ClickHouse 1.1 安装 ClickHouse 安装 YUM 工具包&#xff1a; sudo yum install -y yum-utils添加 ClickHouse YUM 仓库&#xff1a; sudo yum-config-manager --add-repo https://packages.clickhouse.com/rpm/clickhouse.repo安装 ClickHouse 服务器和客户端&…

react+redux+antd-mobile 之 记账本案例

1.环境搭建 //使用CRA创建项目&#xff0c;并安装必要依赖&#xff0c;包括下列基础包 //1. Redux状态管理 - reduxjs/toolkit 、 react-redux //2. 路由 - react-router-dom //3. 时间处理 - dayjs //4. class类名处理 - classnames //5. 移动端组件库 - antd-mobile //6. 请…

linux常见基础指令

入门常见基础指令 ls、stat、 pwd 、cd、tree、 whoami、 touch、 mkdir、 rm 、 man、 cp、mv、cat、tac、echo、>、 >>、 < 、more、 less、 head、 tail、date、 cal、 find、 which、alias、whereis、grep、zip与unzip、 tar、bc、uname、xargs... 热键Tab、…

【信息安全原理】——期末复习(冲刺篇)

&#x1f4d6; 前言&#xff1a;快考试了&#xff0c;做篇期末总结&#xff0c;都是重点与必考点。 题型&#xff1a;简答题&#xff08;45分&#xff09;、协议分析题&#xff08;210分&#xff09;&#xff08;给一个报文或工作流程&#xff0c;分析存在的问题&#xff09;、…