当前位置: 首页 > news >正文

C++ 编程基础(5)类与对象 | 5.5、多态

文章目录

  • 一、多态
    • 1、概念
    • 2、多态实现方式
    • 3、动态绑定与静态绑定
    • 4、虚函数
      • 4.1、声明与定义
      • 4.2、虚函数的工作原理
      • 4.3、虚函数的优点与注意事项
    • 5、不能声明为虚函数的函数
    • 6、纯虚函数
    • 7、抽象类
    • 8、总结

前言:

在C++编程语言中,多态性(Polymorphism)是一项至关重要的特性,它赋予了程序高度的灵活性和可扩展性。多态性允许我们通过一个统一的接口来访问不同类型的对象,从而实现“一个接口,多种实现”的设计理念。

一、多态

1、概念

多态性,顾名思义,指的是“多种形态”或“多种表现”。在C++中,多态性允许我们根据对象的实际类型来调用相应的函数,而不仅仅是根据对象的声明类型。这种机制使得我们可以在不修改现有代码的情况下,轻松扩展程序的功能。

2、多态实现方式

C++主要通过继承和虚函数来实现多态性。

  • 继承: 继承是面向对象编程中的核心概念之一,它允许我们创建新的类(派生类)来继承现有类(基类)的属性和方法。通过继承,我们可以构建出具有层次结构的类体系,为多态性的实现提供了基础。
  • 虚函数: 虚函数是C++中实现多态性的关键。在基类中,可以将某些成员函数声明为虚函数,这意味着这些函数可以在派生类中被重写(Override)。当通过基类指针或引用来调用虚函数时,C++会根据对象的实际类型来调用相应的派生类中的实现,这就是所谓的动态绑定(Dynamic Binding)。

3、动态绑定与静态绑定

虚函数与非虚函数在函数调用时的主要区别在于联编方式的不同。联编是指将源代码中的函数调用解释为执行特定的函数代码块

  • 静态联编: 对于非虚函数,编译器在编译过程中进行联编,即在编译阶段就确定了要调用的函数具体是哪个类中的实现。静态联编效率更高,因此被设置为C++的默认选择。
  • 动态联编: 对于虚函数,编译器生成能够在程序运行时选择正确虚方法的代码。当通过基类指针或引用调用虚函数时,编译器会根据对象的实际类型初始化虚函数表指针,使之指向所属类的虚函数表,从而找到正确的函数进行调用。

4、虚函数

虚函数是实现多态的重要机制,下面重点介绍下虚函数的实现原理

4.1、声明与定义

要在C++中声明一个虚函数,只需在函数声明前加上virtual关键字即可。例如:

class Base {
public:virtual void func() {cout << "Function of Base class" << endl;}
};class Derived : public Base {
public:void func() override { // 使用override关键字确保正确覆盖cout << "Function of Derived class" << endl;}
};

4.2、虚函数的工作原理

虚函数的实现依赖于C++编译器和运行时系统的支持。具体来说,虚函数的实现涉及以下几个关键步骤:

  • 虚函数表(VTable): 每个包含虚函数的类都有一个虚函数表,它是一个函数指针的数组,指向该类及其派生类中所有虚函数的实现。虚函数表在类的定义时就已经被创建,并在对象创建时与对象关联。
  • 虚指针(VPtr): 在包含虚函数的类的对象中,通常会有一个指向虚函数表的指针,称为虚指针。虚指针在对象构造时被设置,指向相应类的虚函数表。
  • 动态绑定: 当通过基类的指针或引用调用虚函数时,C++运行时系统会首先检查对象的虚指针,然后根据虚指针找到对应的虚函数表。接着,根据调用的虚函数在虚函数表中的位置,找到实际的函数指针并调用之。这个过程称为动态绑定,因为它是在运行时根据对象的实际类型来确定调用哪个函数版本的。

4.3、虚函数的优点与注意事项

虚函数的主要优点是提高了代码的灵活性和可扩展性,使得我们能够在不修改基类的情况下改变派生类的行为。然而,在使用虚函数时也需要注意以下几点:

  • 性能开销: 由于虚函数的调用涉及到虚函数表和虚指针的间接访问,因此相对于非虚函数来说有一定的性能开销。在性能敏感的应用场景中,需要谨慎使用虚函数。
  • 内存消耗: 每个包含虚函数的类都会增加一个虚指针的内存开销,用于指向虚函数表。虽然这个开销通常很小,但在大量创建小对象时也可能成为问题。
  • 设计复杂度: 虚函数的使用增加了设计的复杂性,因为需要在基类和派生类之间维护一致的接口和行为。这要求开发者具备较高的设计能力和经验。

5、不能声明为虚函数的函数

在C++中,不能声明为虚函数的有非成员函数、构造函数、静态成员函数、内联成员函数以及友元函数。以下是这些函数的具体介绍:

  • 非成员函数: 非成员函数不属于类的成员,因此无法被继承或重写,也就无法实现多态性。
  • 构造函数: 构造函数在对象创建时调用,而虚函数机制依赖于对象的类型信息(虚表),这在构造对象时尚未完全初始化,因此构造函数不能被声明为虚函数。
  • 静态成员函数: 静态成员函数与特定对象实例无关,而是与类本身相关,因此不支持多态性,不能被声明为虚函数。
  • 内联成员函数: 虽然技术上可以将虚函数声明为内联函数,但这并不常见,因为虚函数的动态绑定特性与内联函数的编译期展开特性存在冲突。
  • 友元函数: 友元函数不是类的成员函数,而是独立于类的外部函数,因此不能被声明为虚函数。

6、纯虚函数

纯虚函数是在基类中声明的函数,但没有提供实现。它的一般形式如下:

virtual ReturnType FunctionName(Parameters) = 0;

这里的 = 0 表示这是一个纯虚函数。由于纯虚函数没有实现,因此包含纯虚函数的类不能实例化。

示例:

class Shape {
public:// 纯虚函数,用于计算面积virtual double area() const = 0;
};

7、抽象类

抽象类是一种不能被实例化的类,它通常用作其他类的基类。抽象类的主要特点是包含一个或多个纯虚函数。这些纯虚函数在抽象类中没有实现,必须在派生类中提供具体实现。具备下面的特征,如下:

  • 抽象性: 抽象类不能被实例化,只能通过其派生类来创建对象。
  • 纯虚函数: 抽象类至少包含一个纯虚函数,纯虚函数没有实现,必须在派生类中重写。
  • 派生类实现: 派生类必须实现所有继承自抽象类的纯虚函数,否则派生类也将成为抽象类。

示例代码:

#include <iostream>
using namespace std;// 抽象基类
class Shape {
public:// 纯虚函数,计算面积virtual double area() const = 0; // 纯虚函数
};// 派生类:矩形
class Rectangle : public Shape {
private:double width;double height;
public:Rectangle(double w, double h) : width(w), height(h) {}// 实现纯虚函数double area() const override {return width * height;}
};// 派生类:圆形
class Circle : public Shape {
private:double radius;
public:Circle(double r) : radius(r) {}// 实现纯虚函数double area() const override {return 3.14159 * radius * radius;}
};int main() {Shape* shapes[2];shapes[0] = new Rectangle(5, 10);shapes[1] = new Circle(7);for (int i = 0; i < 2; i++) {cout << "Area: " << shapes[i]->area() << endl;delete shapes[i];}return 0;
}

8、总结

C++中的多态性是一项强大的特性,它允许通过统一的接口来访问不同类型的对象,从而实现代码的高度复用和灵活扩展。然而,多态性的实现也带来了一定的性能开销和设计复杂度。因此,在使用多态性时,需要权衡其带来的好处和挑战,并根据具体的应用场景和需求来做出合理的选择。

相关文章:

C++ 编程基础(5)类与对象 | 5.5、多态

文章目录 一、多态1、概念2、多态实现方式3、动态绑定与静态绑定4、虚函数4.1、声明与定义4.2、虚函数的工作原理4.3、虚函数的优点与注意事项 5、不能声明为虚函数的函数6、纯虚函数7、抽象类8、总结 前言&#xff1a; 在C编程语言中&#xff0c;多态性&#xff08;Polymorphi…...

客户端发送http请求进行流量控制

客户端发送http请求进行流量控制 实现方式 1&#xff1a;使用 Semaphore (信号量) 控制流量 asyncio.Semaphore 是一种简单的流控方法&#xff0c;可以用来限制并发请求数量。 import asyncio import aiohttp import timeclass HttpClientWithSemaphore:def __init__(self, …...

STM32 低功耗模式详解

目录 一、什么是低功耗 二、低功耗的核心思想 三、STM32的3种低功耗模式 1、睡眠模式 (Sleep Mode) 2、停止模式 (Stop Mode) 3、 待机模式 (Standby Mode) 四、相关电源管理寄存器 1、PWR_CR (Power Control Register, 电源控制寄存器) 2、PWR_CSR (Power Control/St…...

我的第一个PyQt5程序

PyQt5的开发环境配置完成之后&#xff0c;开始编写第一个PyQt5的程序。 方法一&#xff1a;使用将.ui转换成.py文件的方法 import sys from FirstPyQt import Ui_MainWindow from PyQt5.QtWidgets import *#QtCore,QtGui,QtWidgets # from QtTest import Ui_MainWindow#导入Q…...

Unity调用Python

代码如下&#xff1a; if (useAI){/** 通过PaddlePaddle进行合成处理* */// 创建线程参数对象ThreadParameters parameters new ThreadParameters(){pythonPath "python", // 如果 Python 在系统路径中&#xff0c;可以直接使用 "python"pythonScript U…...

前端,location.reload刷新页面

location.reload() 是 JavaScript 中的一个方法&#xff0c;它用于重新加载当前页面。当你调用这个方法时&#xff0c;浏览器会重新加载当前页面的资源&#xff0c;就像用户点击了浏览器的刷新按钮一样。 基本用法 // 刷新当前页面 location.reload();带参数的用法 location…...

5G的发展演进

5G发展的驱动力 什么是5G [远程会议&#xff0c;2020年7月10日] 在来自世界各地的政府主管部门、电信制造及运营企业、研究机构约200多名会议代表和专家们的共同见证下&#xff0c;ITU-R WP 5D#35e远程会议宣布3GPP 5G技术&#xff08;含NB-IoT&#xff09;满足IMT-2020 5G技…...

数据库参数备份

MySQL #!/bin/bash # 获取当前日期和时间的时间戳 TIMESTAMP$(date "%Y%m%d-%H%M%S")# 0、创建目录 mkdir /tmp/parameter_$TIMESTAMP/# 1、获取所有命名空间 echo "1、获取所有命名空间" NAMESPACES$(kubectl get ns | grep qfusion- | grep -v qfusion-…...

PG数据库 数据库时间字段 开始时间和结束时间,判断和查询条件的开始和截止时间存在交集,SQL如何编写

PG 数据库时间字段 开始时间和结束时间&#xff0c;判断和查询条件的开始和截止时间存在交集&#xff0c;SQL如何编写&#xff1f; 在 PostgreSQL 中&#xff0c;如果你想要查询那些时间段&#xff08;由 开始时间 和 结束时间 定义&#xff09;与给定的时间段有交集的记录&am…...

k8s服务内容滚动升级以及常用命令介绍

查看K8S集群所有的节点信息 kubectl get nodes 删除K8S集群中某个特定节点 kubectl delete nodes/10.0.0.123 获取K8S集群命名空间 kubectl get namespace 获取K8S所有命名空间的那些部署 kubectl get deployment --all-namespaces 创建命名空间 web界面上看到的效果,但是…...

机器学习: LightGBM模型(优化版)——高效且强大的树形模型

LightGBM&#xff08;Light Gradient Boosting Machine&#xff09;是一种基于梯度提升决策树&#xff08;GBDT&#xff09;的框架&#xff0c;由微软提出。它具有高效的训练速度、低内存占用、支持并行和GPU加速等特点&#xff0c;非常适合大规模数据的训练任务&#xff0c;尤…...

Wordpress常用配置,包括看板娘跨域等

一个Wordpress的博客已经搭建完成了&#xff0c;那么为了让它看起来更有人间烟火气一点&#xff0c;有一些常用的初始配置&#xff0c;这里整理一下。 修改页脚 页脚这里默认会显示Powered by Wordpress&#xff0c;还有一个原因是这里要加上备案信息。在主题里找到页脚&…...

Python学习从0到1 day27 Python 高阶技巧 ③ 设计模式 — 单例模式

此去经年&#xff0c;再难同游 —— 24.11.11 一、什么是设计模式 设计模式是一种编程套路&#xff0c;可以极大的方便程序的开发最常见、最经典的设计模式&#xff0c;就是我们所学习的面向对象了。 除了面向对象外,在编程中也有很多既定的套路可以方便开发,我们称之为设计模…...

Unity 网格模型及优化

一个模型中可以包含很多网格&#xff0c;一个模型可以由多个网格组成。在Unity3D中一个网格可以由多个子网格&#xff08;Sub-Mesh)组成。 在渲染引擎的时候&#xff0c;每个子网格都要匹配一个材质球来做渲染&#xff0c;实际上一个子网格本身就是一个个普通的模型&#xff0…...

离线 快速搭建 docker docker-compose k8s 环境

所需资源 sealos_5.0.1_linux_arm64.tar.gzkubernetes.tar等docker-compose-linux-aarch64 离线安装sealos&#xff0c;用于安装k8sdocker 首先安装sealos工具 tar zxvf sealos_5.0.1_linux_arm64.tar.gz sealos && chmod x sealos && mv sealos /usr/bin*…...

Excel根据条件动态索引单元格范围

假如我是一个老板&#xff0c;下面有数不胜数的员工&#xff0c;我要检查他们每周的工作产出&#xff0c;列一个排行榜&#xff0c;提高员工积极性&#xff0c;毕竟多劳多得嘛。 每天去手动统计&#xff0c;未免显得不太聪明&#xff0c;我们可以利用公式来解决这个问题。 我们…...

【计算机网络五】HTTP协议!网站运行的奥秘!

目录 HTTP协议 1.HTTP是什么&#xff1f; 2.Fiddler抓包查看HTTP协议格式 3.HTTP请求 4.HTTP响应 HTTP协议 1.HTTP是什么&#xff1f; HTTP ( 全称为 " 超文本传输协议 ") 诞生与 1991 年 . 目前已经发展为最主流使用的一种应用层协议 . HTTP 的前几个版本…...

开源模型应用落地-qwen模型小试-Qwen2.5-7B-Instruct-tool usage入门-Qwen-Agent深入学习(四)

一、前言 Qwen-Agent 是一个利用开源语言模型Qwen的工具使用、规划和记忆功能的框架。其模块化设计允许开发人员创建具有特定功能的定制代理,为各种应用程序提供了坚实的基础。同时,开发者可以利用 Qwen-Agent 的原子组件构建智能代理,以理解和响应用户查询。 本篇将换一种方…...

stream学习

Stream流 定义 Steam流&#xff0c;用于操作集合或者数组中的数据&#xff0c;大量结合了Lamda表达式的语法风格&#xff0c;代码简洁。 重点&#xff1a; 流只能收集一次 ​ 获取Stream流 Stream流要与数据源建立连接。 1.list ​ 直接调用steam()即可 // list List<Stri…...

【数据结构】实验二 单链表的基本操作

一、实验目的 掌握线性表的链式存储结构的表示和实现方法。 掌握链表基本操作的算法实现&#xff0c;以及对相应算法的性能分析。 二、实验内容 1&#xff09;根据输入的一系列整数&#xff0c;以0标志结束&#xff0c;用头插法建立单链表&#xff0c;并输出单链表中各元素…...

跨平台部署YOLOv5的路径陷阱:从WindowsPath错误看Python pathlib的兼容性设计

1. 当WindowsPath遇上Linux&#xff1a;YOLOv5部署的路径陷阱 最近帮朋友调试一个YOLOv5模型部署问题&#xff0c;场景特别典型&#xff1a;在Windows训练好的目标检测模型&#xff0c;迁移到Linux服务器就报错。错误信息直指一个看似简单的路径问题&#xff1a;"NotImple…...

STM32CubeIDE用DAP下载器?这份OpenOCD配置文件修改与复位难题解决指南请收好

STM32CubeIDE深度调优&#xff1a;DAP下载器OpenOCD配置与自动复位难题实战解析 当你在STM32CubeIDE中切换ST-LINK与DAP调试器时&#xff0c;是否注意到两者在用户体验上的显著差异&#xff1f;特别是当使用DAP调试器时&#xff0c;每次下载后都需要手动复位开发板才能运行程序…...

YUI Compressor CSS压缩黑科技:从background-position到media query的全面优化指南

YUI Compressor CSS压缩黑科技&#xff1a;从background-position到media query的全面优化指南 【免费下载链接】yuicompressor YUI Compressor 项目地址: https://gitcode.com/gh_mirrors/yu/yuicompressor YUI Compressor是一款由Yahoo!开发的终极CSS和JavaScript压缩…...

新手福音,用快马AI生成2048论坛登录页,轻松理解Web开发基础

今天想和大家分享一个特别适合新手入门的Web开发小项目——用InsCode(快马)平台快速搭建2048论坛的登录页面。作为刚接触编程的小白&#xff0c;我第一次看到这个需求时有点懵&#xff0c;但通过平台提供的AI生成功能&#xff0c;不仅快速实现了页面&#xff0c;还弄懂了每个环…...

新手福音:借力卓晴式AI,在快马平台轻松完成你的首个网页项目

作为一个刚接触编程的新手&#xff0c;想要创建个人网页却不知从何下手是很常见的情况。最近我发现了一个特别适合新手的组合方案&#xff1a;用AI生成代码在线平台实时调试。下面记录我的完整实践过程&#xff0c;希望能帮到同样想入门的朋友。 明确需求清单 首先梳理出网页需…...

华为 eNSP 安装全攻略:Windows 11 25H2 完美适配

本教程适用范围 ✅ Windows 7&#xff08;所有版本&#xff09;✅ Windows 10&#xff08;所有版本&#xff09;✅ Windows 11 23H2 及以下✅ Windows 11 24H2&#xff08;OS 内部版本 ≥ 26100.3624&#xff09;✅ Windows 11 25H2❌ Windows 11 24H2&#xff08;OS 内部版本…...

NumPy 2.4.4 发布,修复关键错误

NumPy 2.4.4 版本正式发布&#xff0c;作为补丁版本&#xff0c;它修复了 2.4.3 版本的错误&#xff0c;解决了 ARM 平台 OpenBLAS 线程问题&#xff0c;还支持 Python 3.11 - 3.14 版本。 版本修复亮点 NumPy 2.4.4 主要解决了 ARM 平台上的 OpenBLAS 线程问题&#xff0c;即 …...

网络安全有哪些岗位,如何成为一位优秀的网络安全工程师?

网络安全是什么&#xff1f; 首先说一下什么是网络安全&#xff1f; 网络安全工程师工作内容具体有哪些&#xff1f; 网络安全是确保网络系统的硬件、软件及其系统中的数据受到保护&#xff0c;不因偶然的或者恶意的原因而受到破坏、更改、泄露&#xff0c;系统连续可靠正常地…...

超越本地插件:利用快马平台ai能力全面提升你的编码效率与工作流

最近在开发前端项目时&#xff0c;我一直在寻找能提升效率的AI工具。之前用过一些本地IDE插件&#xff0c;虽然能提供基础的代码补全&#xff0c;但功能比较局限。后来尝试了InsCode(快马)平台&#xff0c;发现它把AI辅助开发做到了一个新高度&#xff0c;特别适合需要快速迭代…...

像素剧本圣殿新手指南:RPG对话框系统理解AI输出逻辑与修改技巧

像素剧本圣殿新手指南&#xff1a;RPG对话框系统理解AI输出逻辑与修改技巧 1. 认识像素剧本圣殿的RPG对话框系统 像素剧本圣殿的RPG对话框系统是其最具特色的交互界面&#xff0c;它模拟了经典像素游戏中NPC对话的场景。这个系统不仅仅是视觉上的复古设计&#xff0c;更是AI剧…...