news 2026/6/11 19:20:07

C/C++ 基础笔记(十四)多态与模板编程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C/C++ 基础笔记(十四)多态与模板编程

本篇核心知识:多态(静态 / 动态)、虚函数、析构虚化、重写、final 关键字、纯虚函数与抽象类、成员函数指针、函数模板、类模板、模板友元、模板重载匹配规则

一、多态基础(静态多态 & 动态多态)

概念

多态:同一个调用形式,根据场景执行不同代码。

静态多态(编译期多态):编译阶段确定调用版本,代表:函数重载、运算符重载。

动态多态(运行期多态):运行时依据对象真实类型选择函数,依托继承 + 虚函数 + 基类指针 / 引用实现。

特性

  1. 静态多态:编译绑定,效率高;

  2. 动态多态:运行绑定,灵活,三大必要条件:公有继承、子类重写虚函数、基类指针 / 引用指向派生对象

  3. 普通同名函数(非虚):按指针本身类型调用;虚函数:按指针指向的实际对象类型调用。

代码示例

#include <iostream> using namespace std; class Animal{ public: void speak(){cout<<"动物鸣叫"<<endl;} }; class Pig:public Animal{ public: void speak(){cout<<"小猪哼哼"<<endl;} }; ​ int main(){ Animal* p = new Pig; p->speak(); // 普通函数:输出动物鸣叫 delete p; return 0; } //改成虚函数实现动态多态 class Animal{ public: virtual void speak(){cout<<"动物鸣叫"<<endl;} }; class Pig:public Animal{ public: void speak() override{cout<<"小猪哼哼"<<endl;} }; int main(){ Animal* p = new Pig; p->speak(); // 动态多态:小猪哼哼 delete p; }

相似概念比较

静态多态:编译决议;动态多态:运行决议。

二、虚函数 virtual

概念

基类用 virtual 修饰的成员函数,派生类(子类)可重写函数,是实现动态多态核心。

特性

  1. 非静态成员函数(不加static)可做虚,构造、全局、友元、static 不能定义虚函数;

  2. 派生类重写同名同参函数自动为虚,可加 override 标注;

  3. 虚函数底层依靠虚表、虚指针实现运行查找。

  4. 如果在类内定义,类外实现,类外不需要再使用virtual。

代码示例

class Base{ public: virtual void func(){cout<<"基类虚函数"<<endl;} }; class Son:public Base{ public: void func() override{cout<<"子类重写"<<endl;} };

拓展:override 关键字,强制检查是否合法重写。

三、虚析构函数

概念

基类析构加 virtual,通过基类指针释放派生对象时,先调用派生析构再基类析构,防止派生内存泄漏。

特性

  1. 无虚构造函数(构造不能 virtual);

  2. 有派生设计的基类,析构建议一律 virtual;

  3. 非虚析构:基类指针删子类,仅执行基类析构,子类资源泄漏。

代码示例

class Animal{ public: virtual ~Animal(){cout<<"基类析构"<<endl;} }; class Pig:public Animal{ int* p = new int[5]; public: ~Pig(){delete[] p;cout<<"子类析构"<<endl;} // 如果不写析构释放,子类不会释放内存 }; int main(){ Animal* p = new Pig; delete p; // 先子类再基,正常释放 }

四、final 关键字

概念

修饰类 / 虚函数:final 修饰函数→禁止子类重写;final 修饰类→该类不能被继承。

特性

1 final 虚函数:后续派生类无法重写;

2 final 类:断绝一切继承;

3 final 不能修饰普通非虚函数。

代码示例

class A{ public: virtual void show() final{}; // 不能重写 // virtual void show() = 0 final; // =0 和 final会冲突,不能一起用 }; //class B:public A{}; // 报错 final class C{}; // C不能被继承

五、纯虚函数 & 抽象类

概念

纯虚:virtual 函数() = 0;,无函数体;包含至少一个纯虚的类叫抽象类

特性

  1. 抽象类不能实例化创建对象,仅能定义指针 / 引用;

  2. 子类会继承纯虚函数,必须全部实现父类所有纯虚函数,否则派生仍是抽象类;

  3. 用于定义接口规范。

代码示例

class Animal{ public: virtual void speak() = 0; // 纯虚函数 }; class Pig:public Animal{ // 未实现父类纯虚函数 ​ }; class Dog:public Animal{ // 实现父类纯虚函数 public: void speak(){cout<<"狗叫"<<endl;} }; int main(){ // Animal a; // 报错,抽象类不能创建对象 // Animal* p = new Pig; // 报错,子类未实现父类纯虚函数,也是抽象类不能创建对象 Animal* d = new Dog; // 可执行 d->speak(); }

六、成员函数指针

概念

专门存储类成员函数地址的指针,区别于普通全局函数指针,它是实现 “动态调用成员函数” 的唯一工具。

特性

1 定义格式:返回值 (类名::*指针)(形参)

2 赋值:指针 = &类名::函数名

3 调用:(对象.*指针)(实参)/(对象指针->*指针)(实参)

4 不能跨类指向其他类成员。

作用

1动态调用不同成员函数

2构建函数表、消息映射(框架底层大量用)

3让成员函数作为回调函数

代码示例

class Test{ public: int add(int a,int b){return a+b;} }; int main(){ Test t; Test *pTest = &t; t.add(1,2); int (Test::*p)(int,int) = &Test::add; (t.*p)(3,4); pTest->add(5,6); (pTest->*p)(7,8); }

七、模板总论(泛型编程)

概念

模板:把数据类型做参数,一套代码适配多种类型,分函数模板、类模板,编译期根据实例类型生成对应代码。

特性

1 关键字:template<class T>/template<typename T>等价,一般模板函数:typename,模板类:class

2 模板本身不是可执行代码,实例化后生成实体;

3 模板声明 + 实现建议放同一头文件(分离编译易出错)。

八、函数模板

概念

生成通用函数,任意合法类型均可调用。模板函数不是一个实体函数(缺少数据类型)

特性

1 调用:实参可自动推导类型,推导失败需<类型>显式指定;

2 调用优先级:普通函数 > 模板函数(参数完全匹配优先普通,少传参);

3 支持重载、模板特例化。

代码示例

template<typename T> // template<typename U,typename V,typename K ...> T add(T a,T b){ return a+b; } ​ //模板特例化 template<> MyData add<MyData>(MyData obj1,MyData obj2){ MyData obj; obj.data = obj1.data + obj2.data; return obj; } ​ template<typename T,typename U,typename V> // 可以给默认参数 例如typename V = U 但一般不写 V add1(T a,U b){ return a+b; } ​ int main(){ cout<<add(1,2); // 标准写法add<>() cout<<add(1.5,2.5);// 如果可以根据参数推断出参数类型即可省略<T> cout<<add<double>(3,3.14); cout<<add1<int,double,double>(3,3.14); }

相似比较

普通函数:固定类型;函数模板:类型可变。

拓展:模板与普通函数共存规则

1 参数精准匹配普通→优先普通;

2 普通无法隐式转换匹配→启用模板;

3 强制使用模板:add<int>(3,4)

九、类模板

概念

模板化类,成员类型由模板参数决定,实例化必须显式指定<类型>

特性

1 格式template<class T> class XXX{}

2 类外成员实现需携带模板头;

3 模板类做函数参数:1 固定类型;2 参数写成模板函数。

代码示例

template<class T> class MyVal{ public: T data; MyVal(T d):data(d){} T getData(){return data;} void setData(T v){data = v;}; }; // 模板类的对象作为函数参数 void test1(MyVal<int> &obj){} // 写法一(只能传int型) template<typename T> // 写法二(可以指定Val的对象) void test2(MyVal<T> &obj){} template<typename T> // 写法二(可以指定任何类型) void test3(T &obj){} int main(){ MyVal<int> obj1(10); MyVal<double> obj2(3.14); }

十、模板的友元

概念

模板类内声明友元,分类内实现类外全局实现两种写法。

特性

1 友元写在类体内:写法最简,不需要额外声明,每个模板实例化都会生成对应友元;

2 类外实现:需要前置类声明 + 模板声明,真正全局函数,代码分离符合工程规范。

代码示例

类内实现:

template <class T> class Test { T val; public: Test(T v) : val(v) {} // 友元函数:直接在类内实现 friend void show(Test<T> &t) { // 可以直接访问私有成员 val cout << t.val << endl; } };

类外实现:

// 1. 提前声明模板类 template <class T> class Test; // 2. 提前声明模板友元函数 template <class T> void show(Test<T> &t); // 3. 模板类定义 template <class T> class Test { T val; public: Test(T v) : val(v) {} // 4. 声明【模板友元函数】 注意中间有<> friend void show<>(Test<T>& t); }; // 5. 类外全局实现友元 template <class T> void show(Test<T>& t) { cout << t.val << endl; }

十一、模板特例化(拓展)

概念

对特定类型单独定制模板实现,优先级高于通用模板。

特性

通用模板无法适配某类型(自定义类无 + 运算符),可单独特例。

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

2026年选三维柔性焊接平台犯难?泊头瑞欧量具机械优势全揭

三维柔性焊接平台哪家好&#xff1f;泊头市瑞欧量具机械有限公司值得关注在机械制造、汽车工业、航空航天等众多领域&#xff0c;三维柔性焊接平台都扮演着至关重要的角色。它能大大提高焊接精度和效率&#xff0c;对于保证产品质量起着不可或缺的作用。然而&#xff0c;市场上…

作者头像 李华
网站建设 2026/6/11 19:17:30

突破设备界限:3个智能按键映射方案让你的游戏体验飙升200%

突破设备界限&#xff1a;3个智能按键映射方案让你的游戏体验飙升200% 【免费下载链接】QKeyMapper [按键映射工具] QKeyMapper&#xff0c;Qt开发Win10&Win11可用&#xff0c;不修改注册表、不需重新启动系统&#xff0c;可立即生效和停止。支持游戏手柄映射到键鼠&#x…

作者头像 李华
网站建设 2026/6/11 19:16:56

深入解析NXP OL2311:Sub-1GHz射频接收芯片的设计与应用实战

1. 项目概述&#xff1a;为什么Sub-1GHz射频接收器在今天依然重要&#xff1f;在无线通信领域&#xff0c;2.4GHz和5GHz频段因其高带宽和普及性而备受瞩目&#xff0c;但如果你深入工业控制、智能家居或远程抄表等场景&#xff0c;会发现另一个“沉默的大多数”——Sub-1GHz频段…

作者头像 李华
网站建设 2026/6/11 19:15:52

OpenCore Legacy Patcher完整指南:四步让老旧Mac重获新生

OpenCore Legacy Patcher完整指南&#xff1a;四步让老旧Mac重获新生 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 如果你拥有一台2011年的MacBook Pro或20…

作者头像 李华
网站建设 2026/6/11 19:12:51

Aichat 0.30.0 官方版下载(夸克网盘+百度网盘,SHA256校验)

Aichat 0.30.0 官方版下载&#xff08;夸克网盘百度网盘&#xff0c;SHA256校验&#xff09; 国内访问 GitHub Release 有时较慢&#xff0c;这里把官方 Release 安装包同步到夸克网盘和百度网盘&#xff0c;方便下载。文件来自官方 GitHub Release&#xff0c;本地已按 GitHub…

作者头像 李华
网站建设 2026/6/11 19:11:51

【LuckFox Pico】SPI LCD驱动移植实战:基于FBTFT适配ST7735与GC9306

1. 硬件准备与引脚分析 在开始移植FBTFT驱动之前&#xff0c;首先要确保硬件连接正确。LuckFox Pico开发板通过SPI接口与LCD屏幕通信&#xff0c;我们需要明确每个引脚的功能定义。以ST7735和GC9306两款屏幕为例&#xff0c;它们的典型引脚包括&#xff1a; SCK&#xff1a;SPI…

作者头像 李华