引言:什么是 C++ 中的泛型以及为什么需要它们
在现代编程世界中,代码复用是关键原则之一。如果你为 int 编写了一个求和函数,然后又为 double 和 float 编写了同样的函数,那么迟早你会想要避免重复。正是在这里,泛型(泛型编程)提供了帮助。在 C++ 中,这一概念通过 模板(templates) 实现。
泛型允许你编写适用于任何数据类型的代码,同时不会牺牲性能(与虚函数或 void* 不同)。编译器会为每个具体类型生成函数或类的单独版本,从而提供最大的执行速度。
在本文中,我们将探讨为什么需要在 C++ 中使用泛型,如何正确声明和在实际中使用它们,并介绍常见错误和高级技术。
基本语法:如何声明和使用模板
C++ 中的模板使用关键字 template 和尖括号 <> 声明,尖括号内指定类型参数(通常是 typename 或 class)。
函数模板
最简单的例子——一个返回两个值中最大值的函数:
template <typename T>T max(T a, T b) { return (a > b) ? a : b;}
// 使用:int main() { std::cout << max(3, 7) << std::endl; // 7 std::cout << max(3.14, 2.71) << std::endl; // 3.14 std::cout << max('a', 'z') << std::endl; // z return 0;}请注意:编译器会根据传递的参数自动推导类型 T。如果需要显式指定类型,可以写成 max<double>(3.14, 2.71)。
类模板
模板也适用于类。一个经典的例子——简单的“对”容器:
template <typename T1, typename T2>class Pair {private: T1 first; T2 second;public: Pair(T1 f, T2 s) : first(f), second(s) {} T1 getFirst() const { return first; } T2 getSecond() const { return second; }};
// 使用:Pair<int, std::string> student(1, "Alice");std::cout << student.getFirst() << " " << student.getSecond();这里 T1 和 T2 是模板参数,可以是任何类型。
实际示例:从简单容器到算法
让我们看几个泛型不可或缺的真实场景。
通用排序
编写一个模板函数,用于对任何支持 < 运算符的类型的数组进行排序:
template <typename T>void bubbleSort(T arr[], int n) { for (int i = 0; i < n - 1; ++i) for (int j = 0; j < n - i - 1; ++j) if (arr[j] > arr[j + 1]) std::swap(arr[j], arr[j + 1]);}
// 示例:int intArr[] = {5, 2, 8, 1};bubbleSort(intArr, 4); // 适用于 int
double dblArr[] = {3.14, 2.71, 1.41};bubbleSort(dblArr, 3); // 适用于 double任意数据类型的栈
基于模板实现一个简单的栈:
template <typename T>class Stack {private: std::vector<T> elements;public: void push(const T& value) { elements.push_back(value); } void pop() { if (!elements.empty()) elements.pop_back(); } T top() const { return elements.back(); } bool empty() const { return elements.empty(); }};
// 使用:Stack<int> intStack;intStack.push(10);intStack.push(20);std::cout << intStack.top(); // 20“查找并替换”算法
一个模板函数,用于将容器中所有出现的某个值替换为另一个值:
templa