模板
在学习了如何为特定类型(如 double)设计类(如复数类)和函数后,我们面临一个工程上的核心问题: 当算法逻辑相同,但需要处理的数据类型不同时,我们是否必须为每种类型都重复编写几乎相同的代码?
本篇将介绍C++的“模板”机制,它允许我们编写与类型无关的通用代码,从根本上解决代码复用问题。
模板声明
这是所有模板定义的起点,用于告诉编译器:接下来的代码是一个“模具”,其中包含一个或多个类型参数。
核心概念:模板声明 (Template Declaration)
语法: template typename 和 class 在此处含义完全相同,都表示 T 是一个类型占位符。
作用: 这行代码声明了模板参数列表。T 是一个未绑定的符号,代表某种未来会被指定的数据类型(如 int, double, string, 或自定义的类)。
类模板
当我们需要一个类,其内部某些成员(如数据成员、函数参数/返回类型)的类型可以灵活变化时,就使用类模板。
核心概念:类模板 (Class Template)
定义: 在类定义前加上模板声明,并将类体中需要参数化的具体类型(如 double)替换为模板参数(如 T)。
示例(将复数类改造为模板)
1 | // 1. 声明模板,T是类型占位符 |
常见误区:模板声明的位置
模板声明 template
1 | ❌ 错误示例: |
函数模板
当我们需要一个函数,其逻辑相同但参数类型不同时,使用函数模板。这是C++标准库(如 std::sort, std::max)大量使用的技术。
核心概念:函数模板 (Function Template)
定义: 在函数定义前加上模板声明,将函数的参数类型或返回类型替换为模板参数。
优点: 一次编写,多处使用。编译器会根据调用时的实际类型自动生成对应的函数版本。
示例:通用交换函数和最大值函数
1 | // 1. 交换任意两个同类型变量的值 |
补充:模板代码对类型
T有隐式要求。例如myMax函数要求类型T必须支持>运算符,mySwap要求类型T支持拷贝构造和赋值。 如果使用不支持这些操作的类型,编译器会在实例化时报错,而不是在模板定义时。
这种“在使用时检查”的特性,是C++模板与Java/C#泛型的重要区别之一,也是模板更灵活但也更易出错的原因。
实参推导
对于函数模板,编译器通常能够根据函数调用时传递的实参类型,自动推导出模板参数 T 的具体类型,无需显式指定。
推导规则
- 根据函数调用时的实参类型推导
- 所有实参推导出的类型必须一致
- 无法推导时需显式指定类型
代码示例
1 | template <typename T> |
模板实例化
模板本身不是可执行代码,它只是一个“蓝图”。只有当使用模板并指定具体类型时,编译器才会根据这个蓝图生成实际的类或函数代码,这个过程称为模板实例化。
核心概念:模板实例化 (Template Instantiation)
时机: 发生在编译阶段,而非运行阶段。
结果: 为每个不同的类型组合生成一份独立的代码。
隐式实例化:编译器根据使用自动生成。
显式实例化:程序员手动指定生成特定类型的版本。






