首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【C++ 】模板初阶:从 “重复造轮子” 到通用代码的第一

【C++ 】模板初阶:从 “重复造轮子” 到通用代码的第一

作者头像
用户11872857
发布2025-12-17 16:26:12
发布2025-12-17 16:26:12
170
举报

前言

写 C++ 时,你是不是常为 “int、double 类型要写两套一样逻辑的代码” 而烦?模板就是来解决这个问题的 —— 用泛型编程让一段代码适配多种类型,不用重复造轮子。

📚 C++ 初阶

-【 C++发展史、命名空间、输入输出、缺省参数、函数重载 】

-【 C++引用、内联函数、auto、范围 for、nullptr 】

-【 类和对象(上篇)】

-【 类和对象(中篇)】

-【 C++const成员与日期类 】

-【 类和对象(下篇)】

-【 C/C++内存管理 】



一、泛型编程

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

1. 为什么需要泛型编程?

传统编程中,处理不同类型的数据时,通常会使用函数重载,但这种方式存在明显缺陷:

  • 代码冗余:相同逻辑需为不同类型重复编写,比如 int、double、char 类型的交换函数,仅参数类型不同,函数体完全一致;
  • 维护困难:若需修改算法逻辑(如优化交换逻辑),需逐一修改所有重载版本,易遗漏出错;
  • 扩展性差:新增类型(如自定义结构体)时,需额外添加对应的重载函数,无法灵活适配。
2. 模板的解决方案

模板本质是一种 “代码蓝图”,它允许我们在编写代码时不指定具体数据类型,而是用占位符(模板参数)替代。编译器会在编译(编译阶段)阶段,根据传入的实参类型或显式指定的类型,自动生成对应类型的具体代码,实现 “一次编写,多类型适配” 的效果。


二、函数模板

1. 基本语法

函数模板的定义需以template关键字开头,后跟模板参数列表,语法格式如下:

代码语言:javascript
复制
template<typename T1, typename T2, ..., typename Tn>
返回值类型 函数名(参数列表) 
{
    // 函数体(使用模板参数T1、T2...作为类型)
}

  • 关键字说明:typename用于声明模板参数类型,也可替换为class,二者在模板参数中完全等价(不能用struct(class和strcut的区别之一));
  • 模板参数:可声明多个参数(如T1T2),适配多类型参数的函数场景。

【示例】:通用交换函数

代码语言:javascript
复制
template<typename T>
void Swap(T& a, T& b) 
{
    T temp = a;
    a = b;
    b = temp;
}
2. 核心原理:编译期实例化

函数模板本身不会生成可执行代码,编译器在编译时会根据调用方式,推导模板参数类型并生成具体函数:

  • 调用Swap(1, 2)时,推导Tint,生成Swap<int>函数;
  • 调用Swap(3.14, 5.20)时,推导Tdouble,生成Swap<double>函数;
  • 每个类型对应的函数是独立的,编译后会生成多个不同类型的目标代码。
3. 实例化方式

函数模板支持两种实例化方式,满足不同使用场景:

隐式实例化:编译器根据实参类型自动推导模板参数,无需手动指定(常用);

代码语言:javascript
复制
template<class T>
T Add(const T& a, const T& b) { return a + b; }

int main() 
{
    Add(1, 2);    // 隐式推导T为int
    Add(1.0, 2.0); // 隐式推导T为double
}

显式实例化:手动指定模板参数类型,强制编译器生成对应版本,适用于参数类型不一致的场景;

代码语言:javascript
复制
Add<int>(1, 2.5); // 强制T为int,2.5隐式转换为int

【错误用法】

【正确用法】

1、显式实例化

2、多参数匹配

4. 模板参数匹配原则

当存在非模板函数与模板函数同名时,编译器遵循以下匹配规则:

  1. 优先匹配完全一致的非模板函数(有现成的菜吃现成的);
  2. 若模板能生成更匹配的版本(非模版函数参数不匹配),则选择模板(现成的不好吃,不如吃自己做的);
  3. 模板函数不支持自动类型转换,普通函数支持隐式类型转换。

【示例】:匹配规则演示

代码语言:javascript
复制
// 非模板函数
int Add(int a, int b) { return a + b; }

// 函数模板
template<class T>
T Add(T a, T b) { return a + b; }

int main() 
{
    Add(1, 2);    // 匹配非模板函数
    Add(1, 2.0);  // 匹配模板,生成Add<int, double>
}

三、类模板

1. 基本定义

类模板用于生成通用类,支持不同类型的数据存储和操作,语法格式如下:

代码语言:javascript
复制
template<class T1, class T2, ..., class Tn>
class 类名 
{
    // 类成员定义(成员变量、成员函数可使用模板参数)
};

【示例】:通用栈类

代码语言:javascript
复制
template<typename T>
class Stack 
{
public:
    // 构造函数
    Stack(size_t capacity = 4) 
        : _array(new T[capacity])
        , _capacity(capacity)
        , _size(0) {}
    
    // 成员函数声明
    void Push(const T& data);
    void Pop();
    T Top() const;

private:
    T* _array;      // 存储数据的数组(类型为模板参数T)
    size_t _capacity; // 栈容量
    size_t _size;    // 栈中元素个数
};
2. 类外定义成员函数

类模板的成员函数若在类外定义,需重新声明模板参数列表,并在类名后指定模板参数:

代码语言:javascript
复制
template<class T>
void Stack<T>::Push(const T& data) 
{
    // 扩容逻辑(简化版)
    if (_size >= _capacity) 
    {
        T* temp = new T[_capacity * 2];
        memcpy(temp, _array, sizeof(T) * _size);
        delete[] _array;
        _array = temp;
        _capacity *= 2;
    }
    _array[_size++] = data;
}

template<class T>
void Stack<T>::Pop() 
{
    if (_size > 0) 
    {
        _size--;
    }
}
3. 实例化方式

与函数模板不同,类模板(C++17 前)必须显式指定模板参数,编译器无法自动推导类型:

代码语言:javascript
复制
// 显式实例化int类型栈
Stack<int> intStack;
intStack.Push(10);
intStack.Push(20);

// 显式实例化double类型栈
Stack<double> dblStack;
dblStack.Push(3.14);
dblStack.Push(5.20);

注意:Stack是类名,不是具体类型,Stack<int>Stack<double>才是独立的具体类型。

4. 关键特性

支持默认模板参数:可为模板参数指定默认值,省略部分参数时使用默认值;

代码语言:javascript
复制
template<typename T = int, size_t N = 10>
class Array { /* 实现固定大小数组 */ };

Array<> arr; // 使用默认参数T=int,N=10

静态成员独立:每个实例化类型的类拥有独立的静态成员,互不影响;

代码语言:javascript
复制
template<typename T>
class Foo 
{
public:
    static int count;
};

Foo<int>::count = 0;    // 与Foo<double>::count独立
Foo<double>::count = 0;

【总结】: 函数模板:支持类型推导,编译器根据传递的参数自动推导模板参数。 类模板:不支持类型推导,必须显式指定模板参数类型,因为类的结构和使用方式更复杂,无法通过简单的参数推导出类型。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、泛型编程
    • 1. 为什么需要泛型编程?
    • 2. 模板的解决方案
  • 二、函数模板
    • 1. 基本语法
    • 2. 核心原理:编译期实例化
    • 3. 实例化方式
    • 4. 模板参数匹配原则
  • 三、类模板
    • 1. 基本定义
    • 2. 类外定义成员函数
    • 3. 实例化方式
    • 4. 关键特性
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档