C++面向对象三大特性--多态

C++面向对象三大特性–多态

文章目录

      • C++面向对象三大特性--多态
        • 1.虚函数(Virtual Function)
        • 2.纯虚函数(Pure Virtual Function)和抽象类(Abstract Class)
        • 3.重写(Override)
        • 4.动态绑定(Dynamic Binding)或迟绑定(Late Binding)
        • 5.虚析构函数和纯虚析构
          • 5.1虚析构函数
          • 5.2纯虚析构函数
          • 5.3总结

C++中的多态(Polymorphism)是一种面向对象编程的重要特性,它允许你使用一个接口来表示不同的类型。C++中的多态主要通过虚函数(Virtual Functions)来实现,包括静态多态(编译时多态,主要是函数重载和模板)和动态多态(运行时多态)。下面将介绍C++中动态多态的基础语法:

1.虚函数(Virtual Function)

虚函数是实现动态多态的关键。在基类中声明函数为虚函数,使得派生类可以重写该函数。虚函数的声明需要在基类的函数声明前加上virtual关键字。

class Base {
public:virtual void display() { /* 默认实现 */ }// 注意:析构函数建议声明为虚函数,以确保通过基类指针删除对象时能正确调用派生类的析构函数virtual ~Base() {}
};class Derived : public Base {
public:void display() override { /* 重写实现 */ }
};//
// Created by 86189 on 2024/6/22.
//
#include <iostream>using namespace std;class Animal {
public:virtual void speak() {cout << "Animal speak" << endl;}
};class Dog : public Animal {void speak() override {cout << "Dog speak" << endl;}
};class Cat : public Animal {void speak() override {cout << "Cat speak" << endl;}
};void doWork(Animal &p) {p.speak();
}int main() {Animal *p = new Dog(); // 动态绑定 父类的指针指向子类对象p->speak();Animal *p2 = new Cat();p2->speak();Cat c;Dog d;doWork(c);   //父类的引用指向子类对象doWork(d);delete p;delete p2;return 0;
}
2.纯虚函数(Pure Virtual Function)和抽象类(Abstract Class)

纯虚函数是在基类中没有具体实现的虚函数,要求派生类必须提供实现。含有纯虚函数的类称为抽象类,不能实例化。

class Base {
public:virtual void func() = 0; // 纯虚函数
};// Base类现在是一个抽象类,不能直接创建对象
// Base b; // 错误class Derived : public Base {
public:void func() override { /* 实现 */ }
};//
// Created by 86189 on 2024/6/22.
//
#include <iostream>
using namespace std;class Base {
public:virtual void func() = 0;  //纯虚函数
};//派生类必须重写纯虚函数  否则无法实例化对象
class Derived : public Base {
public:void func() override {cout << "Derived::func()" << endl;}
};int main() {Base *p = new Derived();p->func();return 0;
}
3.重写(Override)

在派生类中重新定义基类的虚函数称为重写。使用override关键字可以明确指出某个函数是重写的意图,同时编译器会进行检查,确保该函数确实是在重写基类的一个虚函数。

class Derived : public Base {
public:void display() override { /* 重写实现 */ }
};
4.动态绑定(Dynamic Binding)或迟绑定(Late Binding)

动态绑定是运行时根据对象的实际类型来决定调用哪个函数的机制。这要求通过基类指针或引用来调用虚函数。如果直接通过对象名调用,则仍然是静态绑定。

Base* basePtr = new Derived();
basePtr->display(); // 运行时会调用Derived类的display()
delete basePtr;
5.虚析构函数和纯虚析构
5.1虚析构函数

基类的析构函数应该声明为虚函数,以确保当通过基类指针删除派生类对象时,能够正确地调用派生类的析构函数,避免内存泄漏。

在多态场景中,如果基类的析构函数不是虚函数,当通过基类指针删除派生类对象时,只会调用基类的析构函数,而派生类特有的资源可能不会被正确释放,从而导致资源泄漏或更严重的问题。

解决这个问题的方法很简单,就是确保所有包含纯虚函数的抽象基类,其析构函数也应该是虚函数。这样,无论通过基类指针指向的是基类对象还是派生类对象,都能够保证调用到正确的析构函数链,从派生类开始,逐级向上调用到基类的析构函数,彻底释放资源。

//
// Created by 86189 on 2024/6/23.
//
#include <iostream>
using namespace std;class Base {
public:virtual void func () = 0;virtual ~Base() {cout << "Base::~Base()" << endl;}
};class Derived : public Base {
public:void func() override {cout << "Derived::func()" << endl;p = new int(10);}~Derived() override {cout << "Derived::~Derived()" << endl;delete p;}int *p{};
};int main() {Derived d;Base *p = new Derived();p->func();delete p;return 0;
}
  • 定义:当在基类中将析构函数声明为虚函数时,它就成为了虚析构函数。声明时不需要赋值为0,格式为 virtual ~ClassName() {}
  • 用途:确保当通过基类指针或引用删除派生类对象时,能够调用到派生类的析构函数,从而正确释放派生类特有的资源。如果不声明为虚析构,那么仅基类的析构函数会被调用,可能导致派生类的资源泄露。
  • 实例化:声明了虚析构函数的类仍然可以实例化对象,不是抽象类。
5.2纯虚析构函数
  • 定义:在基类中将析构函数声明为纯虚函数,即在声明后加上= 0,格式为 virtual ~ClassName() = 0;。需要注意的是,纯虚函数需要在类外提供定义。
  • 用途:与虚析构函数类似,用于确保多态销毁时调用正确的析构函数。但除此之外,声明了纯虚析构函数的类自动成为抽象类。
  • 实例化:拥有纯虚析构函数的类是抽象类,这意味着不能直接实例化此类的对象。抽象类的主要目的是作为其他类的基类,强制要求派生类实现某些纯虚函数(不仅仅是析构函数)。
//
// Created by 86189 on 2024/6/23.
//
#include <iostream>
using namespace std;class Base {
public:virtual ~Base() = 0;  // 纯虚析构函数 确保了派生类中内存可以被释放
};
class Derived : public Base {
public:void func() {cout << "func()" << endl;p = new int(10);}~Derived() override {cout << "~Derived()" << endl;  //纯虚析构保证了释放派生类中申请的内存delete p;p = nullptr;}int *p{};
};Base::~Base() {cout << "Base()" << endl;
}int main() {Derived d;d.func();Base *p = new Derived();delete p;return 0;
}
5.3总结

两者都用于支持多态性下的正确资源管理,但纯虚析构函数额外具有将类定义为抽象类的特性。选择使用哪一种取决于你的设计需求:如果你希望基类可以实例化,并且需要多态性的析构,使用虚析构函数;如果你的基类根本就不应该直接实例化,而总是作为派生类的基类,并且同样需要多态性的析构,那么纯虚析构函数更为合适。

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

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

相关文章

【STM32c8t6】AHT20温湿度采集

【STM32c8t6】AHT20温湿度采集 一、探究目的二、探究原理2.1 I2C2.1. 硬件I2C2.1. 软件I2C 2.2 AHT20数据手册 三、实验过程3.1 CubeMX配置3.2 实物接线图3.3 完整代码3.4 效果展示 四、探究总结 一、探究目的 学习I2C总线通信协议&#xff0c;使用STM32F103完成基于I2C协议的A…

android串口助手apk下载 源码 演示 支持android 4-14及以上

android串口助手apk下载 1、自动获取串口列表 2、打开串口就开始接收 3、收发 字符或16进制 4、默认发送at\r\n 5、android串口助手apk 支持android 4-14 &#xff08;Google seral port 太老&#xff09; 源码找我 需要 用adb root 再setenforce 0进入SELinux 模式 才有权限…

【数据结构导论】自考笔试题:伪代码练习题汇总 1

目录 一、开源项目推荐 二、线性表的基本运算在单链表上的实现 &#xff08;1&#xff09;初始化 &#xff08;2&#xff09;插入 p 指向的新结点的操作 &#xff08;3&#xff09;删除 *p 节点 三、循环链表 &#xff08;1&#xff09;在单链表中 &#xff08;2&…

如何打包数据库文件

使用 mysqldump 命令&#xff1a; mysqldump -u username -p database_name > output_file.sql username 是数据库的用户名。database_name 是要导出的数据库名称。output_file.sql 是导出的 SQL 文件名&#xff0c;可以自定义。 示例&#xff1a; mysqldump -u root -p…

urfread刷算法题day1|LeetCode2748.美丽下标的数目

题目 题目链接 LeetCode2748.美丽下标对的数目 题目描述 给你一个下标从 0 开始的整数数组 nums 。 如果下标对 i、j 满足 0 ≤ i < j < nums.length &#xff0c; 如果 nums[i] 的 第一个数字 和 nums[j] 的 最后一个数字 互质 &#xff0c; 则认为 nums[i] 和 nums…

基于PyTorch设计的全景图合成系统【文末完整工程源码下载】

前言 本项目实现基于PyTorch将多张图片合成为一张全景图。&#xff08;图像存储路径为/images/1&#xff09;。 作者&#xff1a;阿齐Archie&#xff08;联系我微信公众号&#xff1a;阿齐Archie&#xff09; 使用的图片为&#xff1a; 合成后为&#xff1a; 这个全景图项目主…

支持WebDav的网盘infiniCloud(静读天下,Zotero 等挂载)

前言 WebDav是一种基于HTTP的协议&#xff0c;允许用户在Web上直接编辑和管理文件&#xff0c;如复制、移动、删除等。 尽管有一些网盘支持WebDav&#xff0c;但其中大部分都有较多的使用限制。这些限制可能包括&#xff1a;上传文件的大小限制、存储空间的限制、下载速度的限…

Golang日常开发第三方库收集

GUI fltk_go 获取系统系统相关信息 基于go-fltk的分叉版本&#xff0c;项目地址:https://github.com/george012/fltk_go 传送门 Web—>web方向 gin 经典Web框架项目地址:https://github.com/gin-gonic/gin 传送门 跨平台工具 gopsutil 获取系统系统相关信息 基于psu…

多头注意力机制(Multi-Head Attention)

文章目录 多头注意力机制的作用多头注意力机制的工作原理为什么使用多头注意力机制&#xff1f;代码示例 多头注意力机制&#xff08;Multi-Head Attention&#xff09;是Transformer架构中的一个核心组件。它在机器翻译、自然语言处理&#xff08;NLP&#xff09;等领域取得了…

如何打造稳定、好用的 Android LayoutInspector?

速度极慢&#xff0c;遇到复杂的布局经常超时 某些情况无法选中指定的 View 本文将围绕 LayoutInspector 的痛点&#xff0c;分析问题并修复&#xff0c;最终将 LayoutInspector 变成一个稳定、好用的插件。 二、加速 Dump View Hierarchy 2.1 问题描述 开发复杂业务的同学…

Spring Boot + WebSocket 实现 IM 即时通讯

文章目录 1. 项目环境准备2. 配置WebSocket3. 创建消息处理器4. 创建消息类5. 创建前端页面6. 启动应用并测试7. 分析与扩展结论 &#x1f389;欢迎来到SpringBoot框架学习专栏~ ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客&#x1f388;…

Go语言之基础入门

网站&#xff1a;http://hardyfish.top/ 免费书籍分享&#xff1a; 资料链接&#xff1a;https://url81.ctfile.com/d/57345181-61545511-81795b?p3899 访问密码&#xff1a;3899 免费专栏分享&#xff1a; MySQL是怎样运行的从根儿上理解MySQL 课程链接&#xff1a;https:/…

nn.Embedding 根据索引生成的向量有权重吗

import torch import torch.nn as nn 假设有一个大小为 10x3 的 Embedding 层&#xff0c;其中有 10 个单词&#xff0c;每个单词用一个长度为 3 的向量表示 num_words 10 embedding_dim 3 创建 Embedding 层 embedding_layer nn.Embedding(num_words, embedding_dim) p…

LeetCode 算法:翻转二叉树 c++

原题链接&#x1f517;&#xff1a;翻转二叉树 难度&#xff1a;简单⭐️ 题目 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1] 示例 …

【Python】已解决:安装python-Levenshtein包时遇到的subprocess-exited-with-error问题

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例及解决方案五、注意事项 已解决&#xff1a;安装python-Levenshtein包时遇到的subprocess-exited-with-error问题 一、分析问题背景 在安装python-Levenshtein这个Python包时&#xff0c;有时会…

godot所有2D节点介绍

五十个2D节点介绍 2D节点介绍 前言一、Node2D二、sprite2D三、AnimatedSprite2D四、Camera2D五、PhysicsBody2D六、 RigidBody2D七、CharacterBody2D八、StaticBody2D九、joint2D十、DampedSpringJoint2D十一、GrooveJoint2D十二、PinJoint2D十三、Area2D十四、AnimatableBody2…

HTML(21)——CSS精灵

CSS精灵&#xff0c;也叫CSS Sprites,是一种网页图片应用处理方式。把网页中一些背景图片整合到一张图片的文件中&#xff0c;再background-position精确定位出背景图片的位置。 优点&#xff1a;减少服务器被请求的次数&#xff0c;减轻服务器的压力&#xff0c;提高页面加载…

智能优化算法改进策略之局部搜索算子(三)—二次插值法

1、原理介绍 多项式是逼近函数的一种常用工具。在寻求函数极小点的区间&#xff08;即寻查区间&#xff09;上&#xff0c;我们可以利用在若干点处的函数值来构成低次插值多项式&#xff0c;用它作为求极小点的函数的近似表达式&#xff0c;并用这个多项式的极小点作为原函数极…

Java --- 面试题

一、Redis应用场景 1.1、缓存 热点数据(高频查询,但不经常修改和删除的数据)首选redis作为缓存,性能优秀。 案例:如仓储业务中的商品信息,用户从redis的查询商品信息,没有在去数据库中查询。 1.2、分布式锁 在多线程环境下,对共享资源访问的线程问题,需要通过锁的…

快速业务建模

一句话故事 培训学院进行新季度招生工作&#xff0c;出计划后教务处审批&#xff0c;教学秘书下发计划&#xff0c;班主任手机名单审核后完成计划 用户故事 角色 时间线 动作为动名词 业务建模 多次建模&#xff0c;模型是否能完成业务