文章目录
- (一)函数模板和类模板
- 函数模板
- 类模板
- 模板的特化
(一)函数模板和类模板
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; // 输出3std::cout << intStack.pop() << std::endl; // 输出2return 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;
}