C++中的虚函数和多态

C++中的虚函数和多态

虚函数

C++中的虚函数是面向对象编程中的一个核心概念,它允许你在派生类中重写基类中的成员函数。虚函数为多态性提供了机制,使得可以通过基类指针或引用调用派生类中重写的函数。这里是关于虚函数的详细解释:

定义虚函数

在基类中,你可以通过在成员函数声明前加上关键字virtual来定义一个虚函数:

class Base {
public:virtual void show() {std::cout << "Base class show" << std::endl;}
};

重写虚函数

在派生类中,你可以重写基类中定义的虚函数,无需再次使用virtual关键字(尽管加上它也是一个好的实践,以增强代码的可读性):

class Derived : public Base {
public:void show() override { // 使用C++11中的override关键字是个好习惯std::cout << "Derived class show" << std::endl;}
};

虚函数和多态

虚函数使得通过基类指针或引用调用相应的派生类中的函数成为可能,这种机制称为多态。多态允许在不知道对象确切类型的情况下与对象交互:

Base* basePtr = new Derived();
basePtr->show(); // 调用Derived类的show(),而不是Base类的show()

纯虚函数和抽象类

如果一个类中至少有一个纯虚函数,则该类被称为抽象类。纯虚函数是通过在函数声明的末尾加上= 0来指定的,这表示函数没有实现,派生类必须提供实现:

class AbstractBase {
public:virtual void pureVirtualFunc() = 0; // 纯虚函数
};

纯虚函数使得基类能够定义一个接口,而派生类则负责实现该接口。抽象类不能被实例化。

虚析构函数

当通过基类指针删除派生类对象时,为了确保正确调用派生类的析构函数,基类的析构函数应该被声明为虚析构函数:

class Base {
public:virtual ~Base() {// 资源清理代码}
};

如果析构函数不是虚的,那么删除派生类对象的时候可能只会调用基类的析构函数,导致派生类中分配的资源没有被正确释放。

总结

虚函数是实现多态性的基础,它允许你使用基类指针或引用来操作派生类对象,并调用正确的成员函数。这种机制大大增强了语言的灵活性和表达能力,使得代码更加模块化和可扩展。通过纯虚函数和抽象类,C++还允许定义接口,进一步促进了面向对象设计原则的应用。

多态

C++中的多态是面向对象编程的一个核心特性,它允许对象以引用或指针的方式被视为其自身的类型或其基类型。多态性主要通过虚函数(动态多态)和函数重载(静态多态)来实现。这里将主要关注动态多态,因为它更贴近多态的典型用途。

动态多态(运行时多态)

动态多态是在运行时实现的,允许你通过基类的指针或引用来调用派生类的方法。它主要依赖于虚函数和继承。

虚函数

在基类中声明的函数,如果在派生类中被重写,可以声明为虚函数(使用virtual关键字)。当通过基类的指针或引用调用虚函数时,C++运行时会根据对象的实际类型来决定调用哪个版本的函数,这就是多态性的体现。

示例
class Base {
public:virtual void print() {cout << "Base" << endl;}virtual ~Base() {} // 虚析构函数,确保派生类对象的正确清理
};class Derived : public Base {
public:void print() override { // C++11中推荐使用override关键字cout << "Derived" << endl;}
};

使用:

Base* basePtr = new Derived();
basePtr->print(); // 输出 "Derived"
delete basePtr; // 调用正确的析构函数

这段代码展示了多态的典型用法:基类指针指向派生类对象,并调用虚函数print,实际执行的是派生类的print方法。

为什么需要多态

多态允许你编写更通用和可重用的代码。例如,你可以编写一个接受基类指针或引用的函数,并对任何派生类对象进行操作,而无需知道对象的具体类型。这使得代码更加灵活和可扩展。

静态多态(编译时多态)

静态多态是通过函数重载和模板(函数模板和类模板)实现的。这种多态在编译时就已经确定了函数调用的版本,而不是在运行时。

函数重载

在同一个作用域内,可以有多个同名函数,只要它们的参数列表不同(包括参数类型和/或参数数量)。

模板

模板允许你编写与类型无关的代码。函数模板和类模板可以用于创建泛型函数或类。

总结

多态性使得C++程序更加灵活和可扩展,是面向对象编程的一个关键特性。动态多态通过虚函数实现,允许在运行时根据对象的实际类型调用相应的方法。静态多态则在编译时通过函数重载和模板实现,它提供了编译时的类型安全和灵活性。两种形式的多态各有用途,通常在设计和实现C++程序时会根据需要选择使用。

纯虚函数和抽象类

在C++中,纯虚函数和抽象类是面向对象编程中实现接口和抽象基类的重要概念,它们用于定义接口和实现多态。

纯虚函数

纯虚函数是在基类中声明但不提供实现的虚函数。它通过在函数声明的末尾添加= 0来指定。纯虚函数的存在要求派生类必须提供该函数的实现(除非派生类也是一个抽象类)。这样做的目的是为了定义一个接口,强制派生类遵循特定的协议。

示例
class Shape {
public:virtual void draw() = 0; // 纯虚函数virtual ~Shape() {} // 虚析构函数,确保派生类对象的正确清理
};

在这个例子中,Shape类定义了一个纯虚函数draw。任何从Shape派生的类都必须实现draw函数,否则它们也会被视为抽象类。

抽象类

包含至少一个纯虚函数的类被称为抽象类。抽象类不能被实例化,它们的主要用途是作为基类来提供派生类的接口。抽象类可能包含纯虚函数以外的成员函数和数据成员,这些成员函数可以是完全实现的,也可以是虚函数但不是纯虚函数。

示例

考虑上面的Shape类,它是一个抽象类。我们可以派生出具体的形状类,如CircleRectangle,并为它们实现draw方法:

class Circle : public Shape {
public:void draw() override {cout << "Drawing Circle" << endl;}
};class Rectangle : public Shape {
public:void draw() override {cout << "Drawing Rectangle" << endl;}
};

在这里,CircleRectangle都是Shape的具体实现,它们通过覆盖draw方法提供了具体的实现。

使用场景

纯虚函数和抽象类在设计需要多态行为的系统时非常有用。它们允许程序员定义一组接口,然后由派生类提供具体的实现。这种方式提高了代码的模块化和可扩展性,使得新增功能或修改现有功能变得更加灵活和安全。

总之,纯虚函数和抽象类是实现C++中接口和抽象的强大工具,它们使得代码更加通用、灵活,易于维护和扩展。

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

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

相关文章

图像分类从零开始(1)

尽我所能&#xff0c;总结留给后面的师弟们&#xff01; 1.目标 搭建一个完整的系统&#xff0c;包括图像数据集预处理&#xff0c;训练模型&#xff0c;分类器&#xff0c;优化器&#xff0c;以及结果数据处理。 2.理论 3.实例&#xff08;猫狗分类&#xff09; Gitee代码…

GEE数据集——2020年江苏省30米分辨率的地表水数据集

简介 要确保水资源安全并提高应对极端水文事件的能力&#xff0c;就必须全面了解各种尺度的水动态。然而&#xff0c;对季节性水文变化较大的水体进行监测&#xff0c;尤其是使用 Landsat 4-9 等中等分辨率卫星图像&#xff0c;面临着巨大的挑战。本研究引入了基于光谱混合物分…

CentOS7 防火墙(firewalld)常规操作

1.查看、打开、关闭防火墙 1.1.查看防火墙是否运行 systemctl status firewalld [rootlocalhost /]# systemctl status firewalld ● firewalld.service - firewalld - dynamic firewall daemonLoaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor …

3月22日,每日信息差

&#x1f396; 素材来源官方媒体/网络新闻 &#x1f384; 华为云与乐聚签署战略合作协议 &#x1f30d; 我国超重元素研究加速器装置刷新纪录 &#x1f30b; 我国网民规模达10.92亿人&#xff0c;互联网普及率达77.5% &#x1f381; 微软推首批Surface系列AI PC&#xff0c;首度…

C++迈向精通,学习笔记:类与对象

C&#xff1a;类与对象 注意&#xff0c;这是笔记&#xff0c;不是学习手册&#xff01;&#xff01;&#xff01;有可能不适合别人阅读&#xff0c;如果读者有什么问题欢迎在评论区提问&#xff01;&#xff01; 类与对象 不要把类看的多么高深莫测&#xff0c;通过C语言中…

GB/T 35513.2-2017 聚碳酸酯PC模塑和挤出材料检测

聚碳酸酯塑料是一种无味、无臭、无毒、透明的无定形热塑型材料&#xff0c;是分子链中含有碳酸酯的一类高分子化合物的总称。 GB/T 35513.2-2017聚碳酸酯PC模塑和挤出材料测试项目 测试项目 测试标准 熔体体积流动速率 GB/T 3682 拉伸弹性模量 GB/T 1040.2 屈服应力 GB…

基于SSM的土家风景文化管理平台(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的土家风景文化管理平台&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spri…

使用Barrier对齐ConstraintLayout几个控件的最高的一个

前提就是想让一个控件X&#xff0c;对齐A&#xff0c;B&#xff0c;C等控件最高的位置&#xff0c;直接看图。 看&#xff0c;由于name的一行&#xff0c;或者2行&#xff0c;会导致email行的高度&#xff0c;可能比image块高&#xff0c;也可能比image快矮。 那么&#xff…

如何与施耐德Schneider建立EDI连接?

EDI基础知识 何为EDI&#xff1f;是一个软件、系统还是一种流程呢&#xff1f;准确来说&#xff0c;EDI全称Electronic Data Interchange&#xff0c;中文名称是电子数据交换&#xff0c;也被称为“无纸化贸易”。EDI是&#xff1a; 标准化的数据格式连接业务系统间的数据桥梁…

支持开源欧拉openEuler!米尔基于海思Hi3093核心板上市!

新品播报&#xff01;米尔电子发布了基于海思Hi3093高性能MPU的MYC-LHi3093核心板及开发板, 此款核心板支持openEuler embedded OS欧拉系统&#xff0c;丰富生态&#xff0c;可实现100%全国产自主可控。不仅如此&#xff0c;米尔基于Hi3093的核心板及开发板&#xff0c;配套提供…

谷歌浏览器调用相同url数据不刷新

原代码 原因 谷歌浏览访问相同接口默认调用缓存数据 解决方案 添加时间戳

算法打卡day25|回溯法篇05|Leetcode 491.递增子序列、46.全排列、47.全排列 II

算法题 Leetcode 491.递增子序列 题目链接:491.递增子序列 大佬视频讲解&#xff1a;递增子序列视频讲解 个人思路 和昨天的子集2有点像&#xff0c;但昨天的题是通过排序&#xff0c;再加一个标记数组来达到去重的目的。 而本题求自增子序列&#xff0c;是不能对原数组进行…

面试算法-69-三角形最小路径和

题目 给定一个三角形 triangle &#xff0c;找出自顶向下的最小路径和。 每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 1 的两个结点。也就是说&#xff0c;如果正位于当前行的下标 i &#xff0c;那…

NSSCTF Round#11 Basic ez_signin

题目&#xff1a; from Crypto.Util.number import * from secret import flagp getPrime(512) q getPrime(512) assert p > q n p*q e 65536 m bytes_to_long(flag) num1 (pow(p,e,n)-pow(q,e,n)) % n num2 pow(p-q,e,n) c pow(m,e,n)print("num1",num1…

智慧城市的发展趋势与挑战:未来展望

随着信息技术的飞速发展&#xff0c;智慧城市已成为现代城市发展的重要方向。智慧城市通过集成应用先进的信息通信技术&#xff0c;实现城市管理、服务、运行的智能化&#xff0c;为城市的可持续发展注入了新的活力。然而&#xff0c;在智慧城市的发展过程中&#xff0c;也面临…

hadoop namenode 查看日志里面报错8485无法连接

一、通过日志排查问题&#xff1a; 1、首先我通过jpsall命令查看我的进程&#xff0c;发现namenode都没有开启 2、找到问题后首先进入我的日志目录里查看namenode.log [rootnode01 ~]# /opt/yjx/hadoop-3.3.4/logs/ [rootnode01 ~]# ll [rootnode01 ~]# cat hadoop-root-nam…

云农场种植、领养、收获,认养模式新浪潮

​ 小编介绍&#xff1a;10年专注商业模式设计及软件开发&#xff0c;擅长企业生态商业模式&#xff0c;商业零售会员增长裂变模式策划、商业闭环模式设计及方案落地&#xff1b;扶持10余个电商平台做到营收过千万&#xff0c;数百个平台达到百万会员&#xff0c;欢迎咨询。 在…

基于Springboot的疫情物资管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的疫情物资管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

Redis中的缓存雪崩

缓存雪崩 &#x1f914;现象分析 缓存雪崩是指在同一时段大量的缓存key同时失效或者缓存服务(Redis等)宕机&#xff0c;导致大量请求到达数据库&#xff0c;带来巨大压力。 &#x1f44a; 解决方案 利用Redis集群提高服务的可用性&#xff0c;避免缓存服务宕机给缓存业务添…