news 2026/4/17 21:52:41

每日一个C++知识点|面向对象之多态

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
每日一个C++知识点|面向对象之多态

C++面向对象的三大特性是封装,继承,多态。上两篇文章分别讨论了封装和继承,今天主要是讲解C++的另一个面向对象的特性~~多态

多态的概念

什么是多态呢?
多态的核心是"同一个接口,不同的实现"
简单来说,就是调用同一个函数名,程序会根据上下文和调用对象的实际类型来自动执行对应的函数逻辑,后面我们将会用代码来举例说明

多态的分类

C++多态分为静态多态动态多态

静态多态

静态多态是编译时多态,编译器在编译阶段就确定要调用的函数版本,主要通过函数重载、模板实现,用代码举例如下:

#include<iostream>usingnamespacestd;// 重载1:计算两个整数的和intadd(inta,intb){returna+b;}// 重载2:计算三个浮点数的和doubleadd(doublea,doubleb,doublec){returna+b+c;}intmain(){cout<<add(12)<<endl;// 调用int版本,输出3cout<<add(1.12.23.3)<<endl;// 调用double版本,输出6.6return0;}

这里编译器根据参数的个数、类型,在编译时就确定了要调用的add()函数

动态多态

动态多态是运行时多态,程序在运行阶段才确定要调用的函数版本

动态多态的实现需要以下三个条件

  1. 存在继承关系
  2. 父类声明虚函数,子类重写该虚函数
  3. 使用父类的指针指向子类对象

由于还没有说到虚函数,暂时先不用代码举例,等说完虚函数再一并举例

虚函数

上面说到虚函数是动态多态实现的必要条件之一,那么什么是虚函数呢?

普通虚函数

虚函数是在父类中用virtual关键字修饰的成员函数,调用时要根据对象的实际类型来动态绑定,而不是编译时固定绑定

// 父类:图形classShape{public:// 虚函数:绘制图形virtualvoiddraw(){cout<<"绘制基础图形"<<endl;}doublegetArea(){return1;}};

上述代码中,用virtual关键字修饰的draw()函数就是虚函数,调用时要根据对象的实际类型来决定其内容,假如它的子类如下所示:

// 子类:圆形classCircle:publicShape{private:doubleradius;public:Circle(doubler):radius(r){}// 重写父类的虚函数(override关键字可选,但建议加)voiddraw()override{cout<<"绘制半径为"<<radius<<"的圆形"<<endl;}doublegetArea(){returnM_PI*radius*radius;}};

上述代码中子类Circle的成员函数draw()有关键字override来修饰,是对父类虚函数draw()的重写,假如调用情况如下所示:

intmain(){// 父类指针指向子类对象(多态的关键)Shape*shape=newCircle(5.0);// 调用的是子类Circle的draw和getArea(动态绑定)shape->draw();// 输出:绘制半径为5的圆形cout<<"面积:"<<shape->getArea()<<endl;// 输出:面积:78.5398deleteshape;return0;}

由于实际的对象由Shape* shape = new Circle(5.0);决定,所以draw()函数是执行Circle类的内容而不是父类Shape的内容

这就是虚函数的内容,也是动态多态的内容(满足动态多态的三个条件)

虚函数的实现原理

我们已经知道了虚函数的用法,那么虚函数是怎么实现动态多态的呢?下面我们简单了解其原理

编译器为了实现虚函数的动态绑定做了两件事:分别是创建虚函数表添加虚表指针

虚函数表是每个包含虚函数的类(包括父类和子类)都会有一个独立的虚函数表,表中存储了该类所有虚函数的地址。上述代码中Shape类和Circle类都有各自的虚函数表,表中存储虚函数draw()的地址

虚表指针是每个对象会包含一个隐藏的虚表指针,指向所属类的虚函数表。上述代码Shape* shape = new Circle(5.0);中的对象shape存在一个虚函数指针,指向Circle类里的虚函数表里的draw()的地址

当程序运行时,通过对象的虚表指针找到对应的虚函数表,再调用表中的函数地址,从而实现 “根据对象实际类型调用函数”

纯虚函数

上述虚函数的例子是有实际意义的,有时候父类的虚函数没有实现意义,这时可以定义纯虚函数,格式是在函数后加 = 0

classShape{public:// 纯虚函数:没有函数体,强制子类必须重写virtualdoublegetArea()=0;// 普通虚函数可以有默认实现virtualvoiddraw(){std::cout<<"绘制基础图形"<<std::endl;}virtual~Shape(){}};

包含纯虚函数的类称为抽象类,不能实例化对象,只能作为基类被继承,同时子类必须重写所有纯虚函数

虚析构函数

当类中有虚函数时,必须将析构函数声明为虚函数,否则会导致内存泄漏,代码如下:

#include<iostream>#include<cmath>usingnamespacestd;classShape{public:// 1. 业务虚函数(多态的核心接口)virtualvoiddraw()=0;// 纯虚函数,强制子类实现virtualdoublegetArea()=0;// 2. 虚析构函数(配合多态删除场景,必须加)virtual~Shape(){cout<<"Shape析构"<<endl;}};classCircle:publicShape{private:doubleradius;public:Circle(doubler):radius(r){}// 重写业务虚函数voiddraw()override{cout<<"绘制圆形,半径:"<<radius<<endl;}doublegetArea()override{returnM_PI*radius*radius;}~Circle()override{cout<<"Circle析构"<<endl;}};intmain(){// 多态场景:父类指针指向子类对象Shape*shape=newCircle(5.0);shape->draw();// 调用子类的draw(业务虚函数的作用)deleteshape;// 调用子类的析构(虚析构函数的作用)return0;}

上述代码中由于Shape类和Circle类都有虚函数,所以必须要有虚析构函数,避免内存泄漏

如果想更深入了解虚析构函数可以看我往期关于虚析构函数的文章,那里有更具体的描述~

总结

本文通过动态的概念、分类、虚函数、纯虚函数、虚析构函数这几个方面来描述了C++面向对象之多态的内容,并通过具体代码示例来深入分析多态的实现原理和演示多态的实现过程

本文暂时写到这里,如果文章对你有用的话欢迎点赞收藏~

感兴趣的话也可以关注我,我会持续输出C++相关的内容~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 7:51:21

Linly-Talker开源协议解读:个人与商业使用的边界在哪里?

Linly-Talker开源协议解读&#xff1a;个人与商业使用的边界在哪里&#xff1f; 在虚拟主播、AI客服和在线教育日益普及的今天&#xff0c;数字人正从技术概念快速走向真实应用场景。一个普通人只需一张照片和一段文字&#xff0c;就能生成会说话、表情自然的“数字分身”——这…

作者头像 李华
网站建设 2026/4/17 20:52:51

Linly-Talker语音情绪识别功能上线,交互更拟人化

Linly-Talker语音情绪识别功能上线&#xff0c;交互更拟人化 在虚拟主播直播带货时突然语速加快、语气激动&#xff0c;数字人能否立刻“读懂”这份焦急并做出关切回应&#xff1f;当用户用低沉的声音抱怨服务体验&#xff0c;AI客服是否还能保持机械微笑继续念稿&#xff1f;这…

作者头像 李华
网站建设 2026/4/16 20:27:14

基于Android的研学旅行APP设计

SpringBoot基于Android的研学旅行APP设计介绍 该系统以SpringBoot为后端核心框架&#xff0c;结合Android原生开发&#xff08;Java/Kotlin&#xff09;&#xff0c;构建一个集课程管理、行程规划、实时互动、安全监控于一体的综合性研学旅行服务平台。系统通过数字化手段优化研…

作者头像 李华
网站建设 2026/4/16 23:29:03

【Open-AutoGLM进阶必看】:99%人都忽略的定时任务配置陷阱与规避策略

第一章&#xff1a;Open-AutoGLM定时任务配置的核心机制Open-AutoGLM 作为一款面向自动化大语言模型任务调度的开源框架&#xff0c;其定时任务模块依赖于轻量级但高可扩展的调度引擎&#xff0c;实现了任务定义、触发条件与执行策略的解耦。该机制基于 Cron 表达式驱动&#x…

作者头像 李华
网站建设 2026/4/18 8:03:41

任务堆积严重?Open-AutoGLM队列管理实战技巧,立即见效

第一章&#xff1a;任务堆积严重&#xff1f;Open-AutoGLM队列管理实战技巧&#xff0c;立即见效在高并发场景下&#xff0c;Open-AutoGLM常面临任务堆积问题&#xff0c;导致推理延迟上升、资源利用率下降。通过合理的队列管理策略&#xff0c;可显著提升系统吞吐量与响应速度…

作者头像 李华
网站建设 2026/4/18 7:06:52

字节流与字符流读写

一、字节流读写单位&#xff1a;字节 (byte)&#xff0c;即 8 位二进制数。读取方式&#xff1a;它不管你读的是什么文件&#xff08;是图片、视频还是文本&#xff09;&#xff0c;它都把内容当成一串原始的二进制数据来搬运。你的代码&#xff1a;inputStream.read(bytes) 读…

作者头像 李华