(一)函数模板和类模板
C++泛型编程(Generic Programming)是一种编程范式,它允许程序员编写与参数无关的代码,也就是说这些代码可以在多种数据类型上重用,而无需为每个类型重新编写。
泛型编程的主要工具是模板(Templates),主要分为两种类型:函数模板和类模板。
函数模板
函数模板允许程序员编写一个通用的函数,该函数可以接受不同类型的参数,并在编译时根据提供的参数类型生成特定的函数版本。其语法如下:
template<typename T>
return_type functionName(T arg1, T arg2) {
// 函数体
}
- template --- 声明创建模板
- typename --- 表面其后面的符号是一种数据类型,可以用class代替
- T --- 通用的数据类型。T只是一个约定的名称,可以将其改为其他标识符。
- return_type : 返回值的类型,需要根据函数体指定,如:void,int或者T
函数模板的实例化
在使用函数模板时,编译器会根据传递的参数类型自动推导模板参数:
functionName(arg1, arg2); // 自动推导
或者你可以显式指定模板参数:
functionName<int>(arg1, arg2); // 显式实例化
示例:返回两个数中的较大者
#include <iostream>
// 函数模板:返回两个数中的较大者
template<typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
int main() {
std::cout << "Max of 5 and 3: " << max(5, 3) << std::endl;// 调用max<int>(5, 10)
std::cout << "Max of 5.5 and 3.3: " << max(5.5, 3.3) << std::endl;// 调用max<double>(5.5, 3.3)
return 0;
}
Max of 5 and 3: 5
Max of 5.5 and 3.3: 5.5
类模板
类模板则允许你编写一个通用的类,该类可以在编译时根据提供的类型参数生成特定的类版本。基本语法:
template<typename T>
// 类
类模板的定义包括构造函数、成员函数和成员变量等的定义,模板参数在类内部可以用作类型标识符:
template<typename T>
class ClassName {
public:
ClassName(T value); // 构造函数模板
void setValue(T value); // 成员函数模板
private:
T data; // 数据成员
};
// 类模板的析构函数、构造函数和成员函数的实现通常放在类模板定义的外部。
template<typename T>
ClassName<T>::ClassName(T value) : data(value) {}
template<typename T>
void ClassName<T>::setValue(T value) {
data = value;
}
类模板的实例化
在使用类模板时,需要为模板参数指定具体的类型。
ClassName<int> obj(42);
示例:一个通用数据类型的栈数据结构
#include <iostream>
// 类模板:一个简单的栈
template<typename T>
class Stack {
public:
Stack();
~Stack();
void push(T value);
T pop();
private:
T* data;
int top;
const static int size = 100;
};
// 类模板的构造函数
template<typename T>
Stack<T>::Stack() {
data = new T[size];
top = -1;
}
// 类模板的析构函数
template<typename T>
Stack<T>::~Stack() {
delete[] data; // 释放动态分配的数组
}
// 类模板的成员函数:入栈
template<typename T>
void Stack<T>::push(T value) {
data[++top] = value;
}
// 类模板的成员函数:出栈
template<typename T>
T Stack<T>::pop() {
return data[top--];
}
int main() {
Stack<int> intStack;
intStack.push(1);
intStack.push(2);
intStack.push(3);
std::cout << intStack.pop() << std::endl; // 输出3
std::cout << intStack.pop() << std::endl; // 输出2
return 0;
}
模板的特化
模板的特化(Template Specialization)是一种对通用模板进行特殊处理的技术,以适应特定类型或条件的需求,可以分为全特化和偏特化两种类型:
- 全特化:全特化是指对模板的所有模板参数都进行特化处理。例如,如果有一个模板类Test<T1, T2>,全特化可能是为Test<int, char>这样的具体类型提供特定的实现。
- 偏特化:偏特化是指只对部分模板参数进行特化处理。例如,如果有一个模板类Test<T1, T2>,偏特化可能是为Test<T1, char>这样的部分具体类型提供特定的实现,其中T1仍然是一个模板参数。
示例:
#include <iostream>
// 通用模板类定义
template<typename T1, typename T2>
class Test {
public:
void show() {
std::cout << "General template" << std::endl;
}
};
// 全特化示例:为Test<int, char>提供特定实现
template<>
class Test<int, char> {
public:
void show() {
std::cout << "Full specialization for Test<int, char>" << std::endl;
}
};
// 偏特化示例:为Test<T1, char>提供特定实现,其中T1是任意类型
template<typename T1>
class Test<T1, char> {
public:
void show() {
std::cout << "Partial specialization for Test<T1, char>" << std::endl;
}
};
int main() {
// 使用通用模板类
Test<double, double> t1;
t1.show(); // 输出:General template
// 使用全特化类
Test<int, char> t2;
t2.show(); // 输出:Full specialization for Test<int, char>
// 使用偏特化类
Test<float, char> t3;
t3.show(); // 输出:Partial specialization for Test<T1, char>
return 0;
}
对于函数模板,一般采用重载(Overloading)代替特化。例如,如果你有一个函数模板,并且想要为int类型提供特定的实现,你可以简单地重载该函数模板:
#include <iostream>
// 通用函数模板
template<typename T>
void print(T value) {
std::cout << "Generic print: " << value << std::endl;
}
// 重载函数模板,为int类型提供特定实现
void print(int value) {
std::cout << "Specialized print for int: " << value << std::endl;
}
int main() {
print(10); // 调用重载版本,输出 "Specialized print for int: 10"
print(3.14); // 调用通用模板版本,输出 "Generic print: 3.14"
print("Hello"); // 调用通用模板版本,输出 "Generic print: Hello"
return 0;
}