C++——模板(工作中建议不要主动写)

主要内容:

1. 模板 - 实现泛型编程

用途: 模板为我们提供了泛型编程的能力,允许我们编写可以处理多种数据类型的代码,而无需为每种类型都写一遍代码。利用模板,我们可以定义一个通用的算法或数据结构,然后在编译时根据实际需要,将模板中的类型参数替换成具体的类型,从而生成针对特定类型的代码。

关键点:

  • 类型参数: 使用 typenameclass 关键字声明类型参数,例如 typename T
  • 模板实例化: 编译器在遇到使用模板的代码时,会根据实际传入的类型参数生成具体的代码,这个过程称为模板实例化。
  • 函数查找优先级: 编译器在寻找可调用函数时,会优先寻找完全匹配的函数,如果没有找到,才会尝试使用模板生成匹配的函数。

代码示例:

cpp 复制代码
#include <iostream>

template <typename T>
T max(T a, T b) {
  return (a > b) ? a : b;
}

int main() {
  int a = 5, b = 10;
  std::cout << "Max of " << a << " and " << b << " is: " << max(a, b) << std::endl;

  double c = 3.14, d = 2.71;
  std::cout << "Max of " << c << " and " << d << " is: " << max(c, d) << std::endl;
  return 0;
}

讲解: 这个例子定义了一个通用的 max 函数模板,可以比较任意两种类型的值并返回较大的值。在 main 函数中,我们分别使用 intdouble 类型调用 max 函数,编译器会自动生成两个不同版本的 max 函数,分别处理 intdouble 类型。

2. 函数模板

格式:

cpp 复制代码
template<typename T1, typename T2, ..., typename Tn> 
函数返回类型 函数名称 (参数列表) {
  // 函数执行代码
  // 模板类型可以用在函数的任何位置,比如参数列表中的参数类型,返回值类型,执行部分
}

关键点:

  • 声明: 使用 template 关键字和尖括号 <> 声明模板参数列表。
  • 参数列表: 可以有多个模板参数,用逗号分隔。
  • 实例化: 编译器根据函数调用时的参数类型,自动进行模板实例化。

代码示例:

cpp 复制代码
#include <iostream>

template <typename T>
T add(T a, T b) {
  return a + b;
}

int main() {
  int x = 5, y = 10;
  std::cout << "Sum of " << x << " and " << y << " is: " << add(x, y) << std::endl;

  double p = 3.14, q = 2.71;
  std::cout << "Sum of " << p << " and " << q << " is: " << add(p, q) << std::endl;
  return 0;
}

讲解: 这个例子定义了一个通用的 add 函数模板,可以将任意两种相同类型的数值相加。编译器会根据调用 add 函数时传入的参数类型,自动生成相应的函数实例。

3. 类模板

格式:

cpp 复制代码
template<typename T1, typename T2, ..., typename Tn>
class 自定义类型名 {
  // 成员列表 (成员变量, 成员函数)
};

关键点:

  • 声明: 与函数模板类似,使用 template 关键字和尖括号 <> 声明模板参数列表。
  • 定义: 类模板的成员函数一般需要在类外定义,并在定义时也要带上模板参数列表。
  • 实例化: 通过指定具体的类型参数来实例化类模板,例如 MyClass<int> myObject;

代码示例:

cpp 复制代码
#include <iostream>

template <typename T>
class MyArray {
private:
  T* data;
  int size;

public:
  MyArray(int size) : size(size) {
    data = new T[size];
  }

  ~MyArray() {
    delete[] data;
  }

  void set(int index, T value) {
    data[index] = value;
  }

  T get(int index) {
    return data[index];
  }
};

int main() {
  MyArray<int> intArray(5);
  intArray.set(0, 10);
  std::cout << "Value at index 0: " << intArray.get(0) << std::endl;

  MyArray<double> doubleArray(3);
  doubleArray.set(1, 3.14);
  std::cout << "Value at index 1: " << doubleArray.get(1) << std::endl;
  return 0;
}

讲解: 这个例子定义了一个 MyArray 类模板,可以创建一个存储任意类型的数组。在 main 函数中,我们分别实例化了 MyArray<int>MyArray<double>,创建了存储 int 类型和 double 类型的数组。

4. 成员函数模板

关键点:

  • 定义: 类模板的成员函数也可以是模板函数,这意味着一个成员函数可以处理多种类型的参数。
  • 声明: 在类模板内部声明成员函数模板时,需要再次使用 template 关键字和尖括号 <> 声明模板参数列表。
  • 实例化: 在调用成员函数模板时,编译器会根据传入的参数类型自动进行实例化。

代码示例:

cpp 复制代码
#include <iostream>

template <typename T>
class MyContainer {
private:
  T value;

public:
  MyContainer(T value) : value(value) {}

  template <typename U>
  void printWith(U prefix) {
    std::cout << prefix << ": " << value << std::endl;
  }
};

int main() {
  MyContainer<int> intContainer(10);
  intContainer.printWith("Integer");

  MyContainer<double> doubleContainer(3.14);
  doubleContainer.printWith("Double");
  doubleContainer.printWith(123); // 可以传入不同类型的参数
  return 0;
}

讲解: 这个例子定义了一个 MyContainer 类模板,其中包含一个成员函数模板 printWith。这个函数可以接受任意类型的参数 prefix,并将其与容器的值一起打印出来。在 main 函数中,我们分别使用字符串和整数作为 prefix 参数调用 printWith 函数,展示了成员函数模板的灵活性。

相关推荐
先吃饱再说15 小时前
判断回文字符串,从一行代码到双指针优化
算法
黄敬峰18 小时前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术19 小时前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
AI小老六1 天前
SkillOpt 架构拆解:把 Skill 文本当参数,用执行轨迹训练 Agent
后端·算法·ai编程
胡萝卜术1 天前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试
Asize1 天前
初识DFS 与 BFS:递归、队列与图遍历
算法
罗西的思考2 天前
机器人 / 强化学习】HIL-SERL:人类在环驱动的具身智能进化框架
人工智能·算法·机器学习
美团技术团队2 天前
LongCat 开源 VitaBench 2.0:长期动态智能体基准新标杆
人工智能·算法
To_OC2 天前
LC 207 课程表:刚学图论那会儿,我连这是拓扑排序都没看出来
javascript·算法·leetcode