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

C++(23)—模板初阶

文章目录

  • 一、为什么需要泛型编程?
  • 二、函数模板
    • 1. 函数模板的概念
    • 2. 函数模板的语法
    • 3. 函数模板的原理
    • 4. 函数模板的实例化
    • 5. 模板参数匹配规则
  • 三、类模板
    • 1. 类模板的定义
    • 2. 类模板的实例化
  • 四、模板的底层原理
    • 1. 函数模板的编译过程
    • 2. 类模板的编译过程
  • 五、模板的优缺点
  • 六、实战示例:实现动态数组

一、为什么需要泛型编程?

在C++中,若想实现一个通用的交换函数,传统方式需要为不同类型编写多个重载函数:

void Swap(int& a, int& b) { /*...*/ }
void Swap(double& a, double& b) { /*...*/ }
void Swap(char& a, char& b) { /*...*/ }

问题:

代码冗余:仅类型不同,逻辑完全重复维护困难:新增类型需手动添加函数,易出错解决方案:泛型编程(Generic Programming)核心思想:编写与类型无关的通用代码实现工具:模板(Template)

二、函数模板

1. 函数模板的概念

函数模板是一个“蓝图”,编译器根据传入的实参类型自动生成具体函数。
示例:通用交换函数

template<typename T>
void Swap(T& a, T& b) {T tmp = a;a = b;b = tmp;
}

2. 函数模板的语法

关键字:template<typename T1, typename T2, ...>说明:typename可替换为class(但不可用struct)

3. 函数模板的原理

**编译期代码生成:**模板本身不是函数,编译器根据调用时的类型实例化具体函数。

Swap(d1, d2);  // 实例化为 void Swap(double&, double&)
Swap(i1, i2);  // 实例化为 void Swap(int&, int&)

4. 函数模板的实例化

隐式实例化
编译器自动推导类型:

Add(1, 2);      // T推导为int
Add(1.0, 2.0);  // T推导为double

显式实例化
手动指定模板参数类型:

Add<int>(1, 2.5);  // T强制为int,2.5隐式转换为int

5. 模板参数匹配规则

优先匹配普通函数:若存在同名非模板函数,优先调用它。更优匹配选择模板:若模板能生成更匹配的版本,则选择模板。
int Add(int a, int b) { return a + b; }  // 普通函数
template<typename T1, typename T2>
T1 Add(T1 a, T2 b) { return a + b; }     // 模板函数Add(1, 2);     // 调用普通函数
Add(1, 2.0);   // 调用模板生成的 Add(int, double)

三、类模板

1. 类模板的定义

类模板允许定义与类型无关的通用类,常用于容器类(如动态数组、栈、队列)。
**示例:**通用栈类

template<typename T>
class Stack {
public:Stack(size_t capacity = 4) : _array(new T[capacity]), _capacity(capacity), _size(0) {}void Push(const T& data);
private:T* _array;size_t _capacity;size_t _size;
};// 成员函数类外定义
template<typename T>
void Stack<T>::Push(const T& data) {_array[_size++] = data;  // 简化的实现(实际需处理扩容)
}

2. 类模板的实例化

显式实例化:必须指定模板参数类型

Stack<int> intStack;      // 存储int类型的栈
Stack<double> doubleStack; // 存储double类型的栈

四、模板的底层原理

1. 函数模板的编译过程

模板解析:检查模板语法是否正确。实例化:根据调用时的类型生成具体函数。编译生成代码:将实例化的函数编译为二进制指令。

2. 类模板的编译过程

模板解析:检查类模板语法。实例化:根据用户指定的类型生成具体的类。编译成员函数:按需编译成员函数(延迟实例化)。

五、模板的优缺点

优点
代码复用:一套逻辑支持多种类型。

类型安全:编译器自动检查类型错误。性能优化:生成的代码与手写代码效率相同。

缺点
编译时间增加:模板实例化会延长编译时间。

代码膨胀:多类型实例化可能导致生成代码体积增大。

六、实战示例:实现动态数组

template<typename T>
class Vector {
public:Vector() : _data(nullptr), _size(0), _capacity(0) {}void PushBack(const T& val) {if (_size == _capacity) {_capacity = _capacity == 0 ? 1 : _capacity * 2;T* newData = new T[_capacity];// 拷贝旧数据(简化实现,未处理异常)for (size_t i = 0; i < _size; ++i) {newData[i] = _data[i];}delete[] _data;_data = newData;}_data[_size++] = val;}
private:T* _data;size_t _size;size_t _capacity;
};int main() {Vector<int> intVec;intVec.PushBack(1);Vector<string> strVec;strVec.PushBack("hello");return 0;
}
http://www.xdnf.cn/news/50617.html

相关文章:

  • 计算机组成原理笔记(十七)——4.2定点加减运算
  • 再探模板与泛型编程
  • RocketMQ实现基于可靠消息的最终一致性
  • Java处理字符串用啥?String、StringBuilder、StringBuffer
  • Spring Boot自动装配原理(源码详细剖析!)
  • 计算机是如何看待数据的?
  • Java之封装(学习笔记)
  • 算法分析传输加密数据格式密文存储代码混淆逆向保护
  • 4.19-4.20学习总结 网络编程+反射+动态代理
  • AI大模型发展现状与MCP协议诞生的技术演进
  • music21:伍佰 《挪威的森林》MIDI 音乐分析
  • Centos9 离线安装 MYSQL8
  • 【python编程从入门到到实践】第四章 操作列表
  • 进程控制(linux+C/C++)
  • day47——平方数之和(LeetCode-633)
  • javase 学习
  • SQL语句执行顺序
  • QML Universal样式
  • 在 Debian 12 中恢复被删除的 smb.conf 配置文件
  • Python基础总结(八)之循环语句
  • 【RabbitMQ | 第2篇】RabbitMQ 控制台实现消息路由 + 数据隔离
  • 本地化部署ASR服务程序:以FastASR为例
  • 使用 NEAT 进化智能体解决 Gymnasium 强化学习环境
  • 通过 WebSocket 接收和播放 WSS 协议视频流
  • Transformers是一种基于自注意力机制的神经网络模型
  • 王博:影视领域的多元创作先锋,以卓越才华开启新篇章
  • Java——类和对象
  • Nacos深度剖析与实践应用之-配置中心
  • RenderStage::drawInner
  • Vue如何实现样式隔离