1 泛型编程
泛型编程(Generic Programming)是一种编程范式,旨在编写与具体数据类型无关的代码,从而实现代码的重用性和灵活性。在C++中,泛型编程的核心思想是通过模板(template)实现类型参数化,使得函数或类能够适用于多种数据类型
泛型编程的优点
- 代码重用性:无需为每种数据类型单独编写代码,大大减少了代码冗余。
- 类型安全:模板在编译时会进行类型检查,有效避免运行时错误
- 灵活性:可以处理不同类型的数据,而无需修改代码
示例
以下是一个简单的函数模板示例,它可以处理不同类型的数据:
#include <iostream>
using namespace std;
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
cout << add(3, 4) << endl; // 处理int类型
cout << add(3.5, 4.5) << endl; // 处理double类型
return 0;
}
应用
泛型编程广泛应用于标准模板库(STL),如容器、迭代器和算法等。通过使用模板,STL能够提供高效且通用的解决方案
2. 函数模板
函数模板是C++中泛型编程的一个重要部分,它允许你编写独立于任何特定类型的函数。通过使用模板参数,你可以创建一个函数,该函数可以处理不同类型的数据。
2.1 函数模板的定义
函数模板的定义使用 template
关键字,后跟一个模板参数列表。模板参数列表中的每个参数都以 typename
或 class
关键字开头。以下是一个简单的函数模板示例:
#include <iostream>
using namespace std;
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
cout << add(3, 4) << endl; // 处理int类型
cout << add(3.5, 4.5) << endl; // 处理double类型
return 0;
}
在这个示例中,add
函数模板可以接受任意类型的参数,只要这些类型支持加法操作。
2.2 多个模板参数
你还可以定义带有多个模板参数的函数模板。例如,下面的示例展示了一个带有两个模板参数的函数模板:
#include <iostream>
using namespace std;
template <typename T1, typename T2>
auto multiply(T1 a, T2 b) -> decltype(a * b) {
return a * b;
}
int main() {
cout << multiply(3, 4.5) << endl; // 处理int和double类型
return 0;
}
在这个示例中,multiply
函数模板接受两个不同类型的参数,并返回它们的乘积。
2.3 模板实例化
C++中的模板实例化主要有两种方式:隐式实例化和显式实例化。
1. 隐式实例化
隐式实例化是编译器自动完成的。当你在代码中使用模板时,编译器会根据传递的模板参数自动生成相应的实例。例如:
#include <iostream>
using namespace std;
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
cout << add(3, 4) << endl; // 处理int类型,隐式实例化
cout << add(3.5, 4.5) << endl; // 处理double类型,隐式实例化
return 0;
}
在这个例子中,add
函数模板会被隐式实例化为处理 int
和 double
类型的两个不同版本。
2. 显式实例化
显式实例化是由程序员明确指定的。你可以在代码中显式地告诉编译器为特定类型生成模板实例。例如:
#include <iostream>
using namespace std;
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
cout << add<int>(3, 4) << endl; // 使用显式实例化的int版本
cout << add<double>(3.5, 4.5) << endl; // 使用显式实例化的double版本
return 0;
}
3. 类模板
类模板是C++中泛型编程的一个重要部分,它允许你创建可以处理不同数据类型的类。通过使用模板参数,你可以编写一个类,该类可以适用于多种类型的数据。
3.1 类模板的定义
类模板的定义使用 template
关键字,后跟一个模板参数列表。模板参数列表中的每个参数都以 typename
或 class
关键字开头。以下是一个简单的类模板示例:
#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 (elems.empty()) {
throw out_of_range("Stack<>::pop(): empty stack");
}
elems.pop_back();
}
template <class T>
T Stack<T>::top() const {
if (elems.empty()) {
throw out_of_range("Stack<>::top(): empty stack");
}
return elems.back();
}
int main() {
try {
Stack<int> intStack; // int 类型的栈
Stack<string> stringStack; // string 类型的栈
intStack.push(7);
cout << intStack.top() << endl;
stringStack.push("hello");
cout << stringStack.top() << endl;
stringStack.pop();
stringStack.pop();
} catch (exception const& ex) {
cerr << "Exception: " << ex.what() << endl;
return -1;
}
}
3.2 类模板的实例化
类模板的实例化与函数模板类似,可以通过显式实例化和隐式实例化来实现。例如:
Stack<int> intStack; // 隐式实例化
Stack<string> stringStack; // 隐式实例化
3.3类模板的特化
类模板特化允许你为特定类型提供专门的实现。例如:
template <>
class Stack<bool> {
private:
vector<int> elems; // 使用int来存储bool值
public:
void push(bool const& elem) {
elems.push_back(elem ? 1 : 0);
}
void pop() {
if (elems.empty()) {
throw out_of_range("Stack<>::pop(): empty stack");
}
elems.pop_back();
}
bool top() const {
if (elems.empty()) {
throw out_of_range("Stack<>::top(): empty stack");
}
return elems.back() == 1;
}
bool empty() const {
return elems.empty();
}
};