C++ 模板

C++ 模板

一、模板概述

1.1 核心概念

模板是 C++ 泛型编程的核心机制,提供与类型无关的代码复用能力。

  • 作用:一套代码适配多种数据类型,消除重复冗余代码
  • 本质:编译期根据实际类型自动实例化生成对应代码,无运行时开销
  • 两大分类:函数模板、类模板
  • 典型应用:STL 容器(vector/map)、算法、迭代器

1.2 核心关键字

  • template:模板声明起始关键字
  • typename / class:模板类型参数修饰,模板头中完全等价
  • 建议:泛型参数优先使用 typename

二、函数模板

2.1 基础语法

cpp 复制代码
template <typename T>
返回值类型 函数名(参数列表)
{
    // 通用逻辑,不依赖具体类型
}

2.2 基础实战案例:通用最大值

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

template <typename T>
inline T const& Max(T const& a, T const& b)
{
    return a < b ? b : a;
}

int main()
{
    cout << Max(39, 20) << endl;
    cout << Max(13.5, 20.7) << endl;
    cout << Max(string("Hello"), string("World")) << endl;
    return 0;
}

2.3 通用交换函数

cpp 复制代码
#include <iostream>
using namespace std;

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

int main()
{
    int a = 10, b = 20;
    double x = 3.14, y = 6.66;
    swapData(a, b);
    swapData(x, y);
    return 0;
}

2.4 多参数函数模板

cpp 复制代码
#include <iostream>
using namespace std;

template<typename T1, typename T2>
void printTwoData(T1 a, T2 b)
{
    cout << a << " | " << b << endl;
}

int main()
{
    printTwoData(100, "C++模板");
    printTwoData(9.99, false);
    return 0;
}

2.5 函数模板调用方式

  1. 自动类型推导(默认):swapData(a, b)
  2. 手动显式指定类型:swapData<int>(a, b)

2.6 函数模板限制

  • 严格类型匹配,不支持隐式类型转换
  • 参数类型不一致时,需手动强制转换或指定模板参数

三、类模板

3.1 基础语法

cpp 复制代码
template <class T>
class 类名
{
public:
    T 成员变量;
    T 成员函数(T val);
};

3.2 通用栈类实战

cpp 复制代码
#include <iostream>
#include <vector>
#include <stdexcept>
using namespace std;

template <class T>
class Stack
{
private:
    vector<T> elems;
public:
    void push(T const&);
    void pop();
    T top() const;
    bool empty() const { return elems.empty(); }
};

// 类外实现成员函数必须携带模板头
template <class T>
void Stack<T>::push(T const& elem)
{
    elems.push_back(elem);
}

template <class T>
void Stack<T>::pop()
{
    if (empty()) throw out_of_range("栈为空");
    elems.pop_back();
}

template <class T>
T Stack<T>::top() const
{
    if (empty()) throw out_of_range("栈为空");
    return elems.back();
}

int main()
{
    Stack<int> intStack;
    Stack<string> strStack;
    return 0;
}

3.3 自定义通用数组类

cpp 复制代码
#include <iostream>
using namespace std;

template<class T>
class MyArray
{
private:
    T arr[100];
    int size;
public:
    MyArray() : size(0) {}
    void add(T val) { arr[size++] = val; }
    T get(int idx) { return arr[idx]; }
};

int main()
{
    MyArray<int> intArr;
    MyArray<string> strArr;
    intArr.add(666);
    strArr.add("模板编程");
    return 0;
}

3.4 类模板默认参数

cpp 复制代码
#include <iostream>
using namespace std;

// 设置默认类型为 int
template<class T = int>
class Demo
{
public:
    T num;
};

int main()
{
    Demo<> d1;         // 使用默认 int
    Demo<double> d2;   // 自定义类型
    return 0;
}

四、模板特化

4.1 全特化

单一具体类型完全重写模板实现,优先级最高。

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;

// 通用模板
template<class T>
class Compare
{
public:
    bool isEqual(T a, T b)
    {
        return a == b;
    }
};

// char* 全特化版本
template<>
class Compare<char*>
{
public:
    bool isEqual(char* a, char* b)
    {
        return strcmp(a, b) == 0;
    }
};

4.2 偏特化(局部特化)

仅约束部分参数、指针、const 等修饰,仅类模板支持偏特化

cpp 复制代码
#include <iostream>
using namespace std;

// 通用模板
template <typename T>
class DataDeal
{
public:
    void print() { cout << "普通类型处理" << endl; }
};

// 指针类型偏特化
template <typename T>
class DataDeal<T*>
{
public:
    void print() { cout << "指针类型偏特化处理" << endl; }
};

int main()
{
    DataDeal<int> d1;
    DataDeal<int*> d2;
    d1.print();
    d2.print();
    return 0;
}

4.3 特化优先级

全特化 > 偏特化 > 通用模板


五、可变参数模板(C++11)

5.1 语法说明

  • typename... Args:可变参数包
  • args...:参数包展开

5.2 递归展开打印案例

cpp 复制代码
#include <iostream>
using namespace std;

// 递归终止
void printArgs()
{
    cout << endl;
}

// 可变参数模板
template<typename T, typename... Args>
void printArgs(T first, Args... args)
{
    cout << first << " ";
    printArgs(args...);
}

int main()
{
    printArgs(10, 3.14, "C++", 'A', true);
    return 0;
}

5.3 可变参数类模板

cpp 复制代码
template<typename... Args>
class TupleWrap;

template<typename T, typename... Args>
class TupleWrap<T, Args...>
{
private:
    T val;
    TupleWrap<Args...> next;
public:
    TupleWrap(T v, Args... rest) : val(v), next(rest...) {}
    void show() { cout << val << " "; next.show(); }
};

template<>
class TupleWrap<> { public: void show(){} };

六、模板继承

6.1 普通类继承类模板

cpp 复制代码
#include <iostream>
using namespace std;

template<typename T>
class Base
{
protected:
    T data;
public:
    void setData(T d) { data = d; }
    T getData() { return data; }
};

// 普通子类指定具体类型
class Son : public Base<int>
{
public:
    void func() { cout << getData() << endl; }
};

6.2 模板继承模板(泛型继承)

cpp 复制代码
#include <iostream>
using namespace std;

template<typename T>
class Parent
{
protected:
    T num;
};

template<typename T>
class Child : public Parent<T>
{
public:
    // 依赖名称必须加 this->
    void setNum(T n) { this->num = n; }
    void show() { cout << this->num << endl; }
};

关键规则:模板继承中访问父类成员,必须加 this-> 消除编译器依赖歧义。


七、函数模板重载与特化

7.1 重载规则

普通函数 > 模板特化 > 通用模板

cpp 复制代码
#include <iostream>
using namespace std;

template<typename T>
void func(T t) { cout << "通用模板" << endl; }

// 普通函数重载
void func(int t) { cout << "普通函数" << endl; }

// 全特化
template<>
void func<double>(double d) { cout << "double 特化" << endl; }

八、分离编译问题(工程重点)

8.1 问题现象

类模板头文件声明、cpp 文件实现,编译正常,链接报错

8.2 根本原因

模板为延迟实例化,仅在被使用时生成代码;

单独编译 cpp 文件不会实例化模板,链接时找不到函数实现。

8.3 三种解决方案

  1. 推荐:模板声明与实现全部写在头文件
  2. 头文件末尾引入实现文件:#include "xxx.tpp"
  3. 大型项目:显式实例化指定类型

九、核心特性与易错点

9.1 模板核心特性

  1. 编译期实例化,零运行时开销
  2. 强类型安全,杜绝裸指针泛型风险
  3. 多类型实例化会产生代码膨胀
  4. 不支持运行时动态类型

9.2 高频易错点

  1. 类模板必须显式指定类型,无自动推导
  2. 模板外部成员函数必须重写 template
  3. 嵌套依赖类型必须使用 typename 修饰
  4. 模板继承成员访问必须加 this->
  5. 禁止将模板实现拆分到 cpp 文件

十、总结

  1. 函数模板:适配通用算法,自动类型推导
  2. 类模板:构建泛型容器、通用数据结构
  3. 特化:为特殊类型定制逻辑,优化兼容
  4. 可变参数模板:实现万能参数、日志、tuple 等高级能力
  5. 工程规范:模板代码统一存放头文件,规避链接错误
相关推荐
幻影七幻1 小时前
js中send的作用和使用 $.ajax的作用
开发语言·前端·javascript
鸿儒5171 小时前
记录一个C++ Windows程序移植到Linux系统的bug
开发语言·c++·bug
浮尘笔记1 小时前
在Snowy后台无需编码实现自动化生成CRUD操作流程
java·开发语言·经验分享·spring boot·后端·程序人生·mybatis
云动课堂1 小时前
【运维实战】MySQL 8.0 数据库 · 一键自动化部署方案 (适配银河麒麟 V10 / 龙蜥 8 / Rocky Linux 8 / CentOS 8)
linux·运维·数据库
cui_ruicheng1 小时前
Linux进程间通信(一):管道与IPC基础
linux·运维·服务器
MoonBit月兔1 小时前
MoonBit 作为重大成果亮相广东省人工智能应用对接大会,展示 AI 原生编程语言最新进展
开发语言·人工智能·moonbit
Lumos_7771 小时前
Linux -- 互斥锁
linux
Titan20241 小时前
C++11学习笔记
c++·笔记·学习
70asunflower2 小时前
C/C++ 自定义函数的常用规范:从入门到工程实践
c语言·c++