news 2026/2/7 15:09:51

《C++进阶之继承多态》【多态:概念 + 实现 + 拓展 + 原理】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
《C++进阶之继承多态》【多态:概念 + 实现 + 拓展 + 原理】

多态(Polymorphism):是面向对象编程(OOP)的三大核心特性之一,它允许同一操作作用于不同的对象时,可以产生不同的行为。

  • 简单说,就是 “一个行为,多种形态”,通过统一的接口处理不同类型的对象,从而提高代码的灵活性和可扩展性。

多态的本质“一种接口,多种实现”以下从 C++ 的角度,分编译时多态运行时多态详细解析:


多态的核心价值:是解耦“接口使用”“具体实现”

  • 调用者只需关注 “做什么”(接口),无需关心 “怎么做”(具体实现)
  • 不同对象通过同一接口调用时,会自动执行自身的实现逻辑

C++ 中的多态分类编译时多态(静态多态)运行时多态(动态多态)核心区别在于:确定调用哪个实现的时机(编译阶段 vs 运行阶段)

------------多态的实现------------

① 静态多态的实现

静态多态:通过函数重载模板编译期根据调用参数确定具体执行的函数。

  • 特点:行为确定于编译阶段,效率高,属于 “静态绑定”。

示例 1函数重载(同一作用域的同名函数,参数不同)

代码语言:javascript

AI代码解释

#include <iostream> using namespace std; // 重载:根据参数类型/数量,编译期确定调用哪个函数 int Add(int a, int b) { return a + b; } double Add(double a, double b) { return a + b; } int main() { //1.编译期确定调用 Add(int, int) cout << Add(1, 2) << endl; //2.编译期确定调用 Add(double, double) cout << Add(1.5, 2.5) << endl; return 0; }

在这里插入图片描述

示例 2模板(泛型编程,编译期生成具体代码)

代码语言:javascript

AI代码解释

#include <iostream> using namespace std; // 模板:编译期根据 T 的类型,生成对应函数 template <typename T> T Add(T a, T b) { return a + b; } int main() { //1.编译期生成 Add<int>(int, int) cout << Add(1, 2) << endl; //2.编译期生成 Add<double>(double, double) cout << Add(1.5, 2.5) << endl; return 0; }

在这里插入图片描述

② 动态多态的实现

动态多态:通过虚函数继承运行期根据对象的实际类型确定调用的函数。

  • 特点:行为确定于运行阶段,支持动态扩展,属于 “动态绑定”。

核心条件(三要素):

  • 继承:派生类继承基类。
  • 虚函数:基类声明 virtual 函数,派生类重写(override)该虚函数。
  • 基类指针/引用:通过基类指针或引用调用虚函数,指向派生类对象。
虚函数

虚函数(Virtual Function):是在基类中声明的、使用virtual关键字修饰的成员函数。

  • 虚函数是 C++ 实现动态多态的核心机制。
  • 虚函数的目的是为派生类提供一个可重写的接口。
  • 虚函数会让程序在运行时根据对象的实际类型调用对应的函数实现。

任务1基类声明虚函数

代码语言:javascript

AI代码解释

/*---------------------定义:“基类:Shape类”---------------------*/ class Shape { public: virtual void Draw() //基类声明 virtual,为派生类提供重写接口 { cout << "画一个形状" << endl; } };
重写

重写(Override):是派生类重新实现基类中已声明的虚函数,让同一接口在不同派生类中有不同行为。

  • 重写是 C++ 面向对象编程中实现动态多态的关键机制。

重写的严格规则(三同原则 + 协变返回)派生类重写基类虚函数时,需满足以下条件,否则会变成“隐藏”而非“重写”1. 三同原则(基本规则)

  • 函数名相同:派生类函数名必须与基类虚函数完全一致
  • 参数列表相同:参数的类型、数量、顺序必须完全一致
  • 返回值类型相同:C++ 要求返回值类型严格一致,除非是协变返回类型

任务2派生类重写虚函数

代码语言:javascript

AI代码解释

/*---------------------定义:“派生类:Circle类”---------------------*/ class Circle : public Shape { public: //1.派生类重写基类虚函数Draw() void Draw() { cout << "画一个圆" << endl; } }; /*---------------------定义:“派生类:Rectangle类”---------------------*/ class Rectangle : public Shape { public: //1.派生类重写基类虚函数Draw() void Draw() { cout << "画一个矩形" << endl; } };
协变

2. 协变返回(特殊情况)协变返回类型:是指若基类虚函数返回基类指针/引用,派生类重写的函数可返回派生类指针/引用,仍视为重写。

代码语言:javascript

AI代码解释

class Base { public: virtual Base* Clone() // 基类虚函数返回 Base* { return new Base(); } }; class Derived : public Base { public: Derived* Clone() // 派生类重写,返回 Derived*(协变返回) { return new Derived(); } };

代码示例1:运行时多态的实现

代码语言:javascript

AI代码解释

#include <iostream> using namespace std; /*---------------------定义:“基类:Shape类”---------------------*/ class Shape { public: //1.基类定义虚函数Draw() virtual void Draw() //基类声明 virtual,为派生类提供重写接口 { cout << "画一个形状" << endl; } }; /*---------------------定义:“派生类:Circle类”---------------------*/ class Circle : public Shape { public: //1.派生类重写基类虚函数Draw() void Draw() { cout << "画一个圆" << endl; } }; /*---------------------定义:“派生类:Rectangle类”---------------------*/ class Rectangle : public Shape { public: //1.派生类重写基类虚函数Draw() void Draw() { cout << "画一个矩形" << endl; } }; int main() { //1.基类指针指向派生类对象 Shape* shape1 = new Circle(); Shape* shape2 = new Rectangle(); //2.运行时根据对象实际类型,调用对应 Draw 函数 shape1->Draw(); // 输出:画一个圆(Circle 的 Draw) shape2->Draw(); // 输出:画一个矩形(Rectangle 的 Draw) delete shape1; delete shape2; return 0; }

在这里插入图片描述

代码示例2:运行时多态的实现

代码语言:javascript

AI代码解释

#include <iostream> using namespace std; /*---------------------定义:“基类:Person类”---------------------*/ class Person { public: virtual void BuyTicket() //基类声明 virtual,为派生类提供重写接口 { cout << "买票-全价" << endl; } }; /*---------------------定义:“派生类:Student类”---------------------*/ class Student : public Person { public: virtual void BuyTicket() //重写基类的虚函数 BuyTicket { cout << "买票-打折" << endl; } }; void Func(Person* ptr) //注意:通过基类指针调用虚函数,实际执行的是指针指向对象的重写版本 { ptr->BuyTicket(); /* 多态的核心逻辑: * 1.虽然调用的是 Person 指针的 BuyTicket, * 2.但实际执行的函数由 ptr 指向的对象的真实类型决定(Person 或 Student) * 3.这就是运行时多态(动态绑定)的体现 */ } int main() { //1.创建:“基类 + 派生类”的对象 Person ps; Student st; //2.调用 Func 函数,分别传入“Person + Student”对象的地址 Func(&ps); //ptr 是 Person* 类型,指向 Person 对象,调用 Person::BuyTicket Func(&st); //ptr 是 Person* 类型,但指向 Student 对象,调用 Student::BuyTicket(重写版本) return 0; }

在这里插入图片描述

在这里插入图片描述

------------多态的拓展------------

1. override的意义与使用?

在 C++ 中,派生类重写基类虚函数时,即使派生类的函数不加virtual关键字,也能构成重写。 这是因为:基类的虚函数被继承到派生类后,会自动保持 “虚函数” 的属性,无需重复声明 virtual


但这种写法不规范,原因有二:

  • 可读性差:其他开发者阅读代码时,无法直观识别这是虚函数重写。
  • 维护风险:若后续修改基类(如:删除虚函数关键字 ),派生类的重写逻辑会被破坏,且难以排查。

因此C++11 及以上建议用 override 关键字显式标记重写,既规范又能让编译器帮你检查重写是否正确(如:函数名、参数不匹配时会报错 )

代码语言:javascript

AI代码解释

#include <iostream> using namespace std; /*---------------------定义:“基类:Animal类”---------------------*/ class Animal { public: virtual void makeSound() { cout << "动物发出声音" << endl; } }; /*---------------------定义:“派生类:Dog类”---------------------*/ class Dog : public Animal { public: //写法1:隐式重写(不推荐) void makeSound() { cout << "汪汪汪!" << endl; } }; /*---------------------定义:“派生类:Cat类”---------------------*/ class Cat : public Animal { public: //写法2:显式用override标记(推荐) void makeSound() override { cout << "喵喵喵~" << endl; } }; /*---------------------测试函数:通过基类指针调用虚函数---------------------*/ void playSound(Animal* animal) { animal->makeSound(); //多态调用 } int main() { //1.创建:“基类 + 派生类”的对象 Animal generic; Dog dog; Cat cat; //2.调用playSound函数进行多态调用 playSound(&generic); // 输出:动物发出声音 playSound(&dog); // 输出:汪汪汪! playSound(&cat); // 输出:喵喵喵~ return 0; }

在这里插入图片描述

2. final关键字怎么使用?

final 关键字:用于限制类的继承虚函数的重写,增强代码的安全性和可维护性。


final关键字有两种用法

  • 修饰类:禁止该类被继承(即该类不能作为基类)
  • 修饰虚函数:禁止派生类重写该虚函数

1. 修饰类(禁止继承)

代码语言:javascript

AI代码解释

#include <iostream> using namespace std; class Base { // 基类成员 }; class Derived final : public Base //注意:使用 final 修饰,禁止被继承 { // 最终派生类成员 }; class IllegalDerived : public Derived //编译错误:无法从 final 类 Derived 派生 { // ... }; int main() { //1.创建“最终派生类”的对象 Derived d; //正确:可以正常创建 final 类的对象 cout << "成功创建 Derived 对象(final 类)" << endl; //2.创建“继承最终派生类”的对象 IllegalDerived i; //错误:无法实例化从 final 类派生的类 return 0; }

在这里插入图片描述

2. 修饰虚函数(禁止重写)

代码语言:javascript

AI代码解释

#include <iostream> using namespace std; class Base { public: //1.声明虚函数,允许派生类重写 virtual void func() { cout << "Base::func()" << endl; } //2.声明虚函数并用 final 修饰,禁止派生类重写 virtual void finalFunc() final { cout << "Base::finalFunc()" << endl; } }; class Derived : public Base { public: //1.正常重写非 final 的虚函数 void func() override { cout << "Derived::func()" << endl; } //2.编译错误:void Derived::finalFunc() 重写 final 函数 void finalFunc() override { cout << "Derived::finalFunc()" << endl; } }; int main() { //1.测试虚函数重写 Base* ptr = new Derived(); ptr->func(); // 调用 Derived::func()(多态) //2.测试 final 函数 ptr->finalFunc(); // 错误:Derived::finalFunc() 无法重写 Base::finalFunc() delete ptr; return 0; }

在这里插入图片描述

3. 析构函数是怎么进行重写的?

在 C++ 中,当基类的析构函数被声明为虚函数时,只要派生类定义了析构函数,无论是否添加virtual关键字,该派生类析构函数都会与基类析构函数构成重写。

  • 尽管基类析构函数(如:~Base())和派生类析构函数(如:~Derived())名字不同,看似不符合重写 “函数名相同” 的规则。
  • 但实际上编译器会对析构函数名称做特殊处理,将编译后的名称统一处理为destructor,从而实现重写机制。

通过下面的代码示例可以看到:

  • 如果基类析构函数~A()没有加virtual修饰,那么在执行delete p2时,只会调用基类A的析构函数,而不会调用派生类B的析构函数。
  • 若派生类B的析构函数~B()中包含资源释放的逻辑,这种情况就会导致资源无法正常释放,进而引发内存泄漏问题 。

www.dongchedi.com/article/7597217223819772478
www.dongchedi.com/article/7597215233471889944
www.dongchedi.com/article/7597216873696526910
www.dongchedi.com/article/7597217143041737241
www.dongchedi.com/article/7597214870441935385
www.dongchedi.com/article/7597214599947043353
www.dongchedi.com/article/7597214580846477886
www.dongchedi.com/article/7597216071082738201
www.dongchedi.com/article/7597214433031078424
www.dongchedi.com/article/7597214537498362392
www.dongchedi.com/article/7597215399566361150
www.dongchedi.com/article/7597215658752868888
www.dongchedi.com/article/7597215102077141528
www.dongchedi.com/article/7597214696924004889
www.dongchedi.com/article/7597213042329895448
www.dongchedi.com/article/7597215125493400126
www.dongchedi.com/article/7597212587801018905
www.dongchedi.com/article/7597214580846215742
www.dongchedi.com/article/7597214267869692440
www.dongchedi.com/article/7597213056480969278
www.dongchedi.com/article/7597212812516639257
www.dongchedi.com/article/7597212812516868633
www.dongchedi.com/article/7597213320844182041
www.dongchedi.com/article/7597211160895046206
www.dongchedi.com/article/7597211076186374681
www.dongchedi.com/article/7597212587801477657
www.dongchedi.com/article/7597210839670080062
www.dongchedi.com/article/7597210276412899864
www.dongchedi.com/article/7597211030086926872
www.dongchedi.com/article/7597211160895078974
www.dongchedi.com/article/7597209997126238744
www.dongchedi.com/article/7597209064238039577
www.dongchedi.com/article/7597211030087287320
www.dongchedi.com/article/7597209862904480318
www.dongchedi.com/article/7597209319725253145
www.dongchedi.com/article/7597208525277987353
www.dongchedi.com/article/7597208525278151193
www.dongchedi.com/article/7597210268858958398
www.dongchedi.com/article/7597209475426435609
www.dongchedi.com/article/7597209772429476377
www.dongchedi.com/article/7597201951176213017
www.dongchedi.com/article/7597201687174562366
www.dongchedi.com/article/7597199724889997849
www.dongchedi.com/article/7597199550092657177
www.dongchedi.com/article/7597200248943329816
www.dongchedi.com/article/7597199001863701017
www.dongchedi.com/article/7597198298541834777
www.dongchedi.com/article/7597200591446000190
www.dongchedi.com/article/7597199968348357145
www.dongchedi.com/article/7597199312984162841
www.dongchedi.com/article/7597199429019861566
www.dongchedi.com/article/7597196791863902782
www.dongchedi.com/article/7597197725960110616
www.dongchedi.com/article/7597197533550920217
www.dongchedi.com/article/7597196766895079960
www.dongchedi.com/article/7597197878439756313
www.dongchedi.com/article/7597196909912031768
www.dongchedi.com/article/7597195764053492248
www.dongchedi.com/article/7597196370181030424
www.dongchedi.com/article/7597195961618121241
www.dongchedi.com/article/7597195004385182232
www.dongchedi.com/article/7597196281857442366
www.dongchedi.com/article/7597195368090075673
www.dongchedi.com/article/7597195809683505689
www.dongchedi.com/article/7597194439940932158
www.dongchedi.com/article/7597194164794933822
www.dongchedi.com/article/7597194060553749016
www.dongchedi.com/article/7597195414877995544
www.dongchedi.com/article/7597194911112479256
www.dongchedi.com/article/7597194219174068761
www.dongchedi.com/article/7597192718418756120
www.dongchedi.com/article/7597191743318065689
www.dongchedi.com/article/7597194069471003161
www.dongchedi.com/article/7597193401016500760
www.dongchedi.com/article/7597192147254772286
www.dongchedi.com/article/7597192394672505406
www.dongchedi.com/article/7597190301329080894
www.dongchedi.com/article/7597188998091833881
www.dongchedi.com/article/7597190006675243582
www.dongchedi.com/article/7597189866363372056

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

DeepSeek-R1-Distill-Qwen-1.5B降本方案:T4显卡低成本部署实战案例

DeepSeek-R1-Distill-Qwen-1.5B降本方案&#xff1a;T4显卡低成本部署实战案例 在当前大模型快速发展的背景下&#xff0c;如何在有限硬件资源下实现高性能推理成为企业落地AI应用的关键挑战。本文聚焦于DeepSeek-R1-Distill-Qwen-1.5B这一轻量化大模型&#xff0c;结合vLLM推…

作者头像 李华
网站建设 2026/2/6 16:03:00

WeChatFerry微信机器人终极使用指南

WeChatFerry微信机器人终极使用指南 【免费下载链接】WeChatFerry 微信逆向&#xff0c;微信机器人&#xff0c;可接入 ChatGPT、ChatGLM、讯飞星火、Tigerbot等大模型。Hook WeChat. 项目地址: https://gitcode.com/GitHub_Trending/we/WeChatFerry 在当今数字化办公时…

作者头像 李华
网站建设 2026/2/4 2:52:33

R3nzSkin:英雄联盟安全换肤技术深度解析

R3nzSkin&#xff1a;英雄联盟安全换肤技术深度解析 【免费下载链接】R3nzSkin Skin changer for League of Legends (LOL).Everyone is welcome to help improve it. 项目地址: https://gitcode.com/gh_mirrors/r3n/R3nzSkin R3nzSkin作为一款专业的英雄联盟内存级换肤…

作者头像 李华
网站建设 2026/2/5 4:04:35

25元打造AI智能眼镜:手把手DIY制作教程

25元打造AI智能眼镜&#xff1a;手把手DIY制作教程 【免费下载链接】OpenGlass Turn any glasses into AI-powered smart glasses 项目地址: https://gitcode.com/GitHub_Trending/op/OpenGlass 还在为昂贵的智能眼镜望而却步吗&#xff1f;现在只需25元&#xff0c;你就…

作者头像 李华
网站建设 2026/2/4 6:43:36

CosyVoice-300M Lite医疗场景应用:电子病历语音化部署案例

CosyVoice-300M Lite医疗场景应用&#xff1a;电子病历语音化部署案例 1. 引言 随着智能语音技术的快速发展&#xff0c;语音合成&#xff08;Text-to-Speech, TTS&#xff09;在医疗信息化领域的应用正逐步深入。医生在日常诊疗过程中需要频繁记录患者病情、检查结果和治疗方…

作者头像 李华
网站建设 2026/2/4 6:59:43

如何高效使用B站成分检测器:智能识别用户背景的必备工具

如何高效使用B站成分检测器&#xff1a;智能识别用户背景的必备工具 【免费下载链接】bilibili-comment-checker B站评论区自动标注成分&#xff0c;支持动态和关注识别以及手动输入 UID 识别 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-comment-checker 在…

作者头像 李华