1. 模板overview
1.1 what is 模板
模板 is C++inimplementation泛型programming coremechanism, 它允许我们writing and class型无关 code. through模板, 我们可以creation适用于不同dataclass型 function and class, 而不需要 for 每种class型重复writing相同 code.
模板 主要优势including:
- code复用: writing一次code, 适用于 many 种dataclass型.
- class型security: in 编译时forclass型check, 避免run时error.
- flexible性: 可以processing不同class型 parameter and return value.
- efficiency: 模板 in 编译时instance化, 不会引入run时开销.
1.2 模板 class型
C++in has 两种主要class型 模板:
- function模板 (Function Templates) : 用于creation可以processing不同class型parameter function.
- class模板 (Class Templates) : 用于creation可以processing不同class型成员 class.
2. function模板
2.1 function模板 定义
function模板 定义usingtemplate关键字, after 跟模板parameterlist, 然 after is function定义.
template <typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}
// or 者using class 关键字 (效果相同)
template <class T>
T minimum(T a, T b) {
return (a < b) ? a : b;
}
2.2 function模板 using
usingfunction模板时, 编译器会根据传入 parameterclass型自动推断模板parameterclass型, or 者我们可以显式指定模板parameterclass型.
#include <iostream>
using namespace std;
template <typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}
template <class T>
T minimum(T a, T b) {
return (a < b) ? a : b;
}
int main() {
// 自动class型推断
int a = 10, b = 20;
cout << "最 big 值: " << maximum(a, b) << endl;
cout << "最 small 值: " << minimum(a, b) << endl;
double c = 3.14, d = 2.71;
cout << "最 big 值: " << maximum(c, d) << endl;
cout << "最 small 值: " << minimum(c, d) << endl;
string e = "apple", f = "banana";
cout << "最 big 值: " << maximum(e, f) << endl;
cout << "最 small 值: " << minimum(e, f) << endl;
// 显式指定模板parameter
cout << "最 big 值: " << maximum<int>(100, 200) << endl;
cout << "最 small 值: " << minimum<double>(1.5, 2.5) << endl;
return 0;
}
2.3 function模板 重载
function模板可以被重载, 我们可以 for specificclass型providing专门 模板重载version.
#include <iostream>
#include <cstring>
using namespace std;
template <typename T>
T maximum(T a, T b) {
cout << "usingcommon模板" << endl;
return (a > b) ? a : b;
}
// for const char* class型providing重载
template <>
const char* maximum(const char* a, const char* b) {
cout << "using const char* 特化模板" << endl;
return (strcmp(a, b) > 0) ? a : b;
}
// 普通function重载 (priority high 于模板)
double maximum(double a, double b) {
cout << "using普通function" << endl;
return (a > b) ? a : b;
}
int main() {
int a = 10, b = 20;
cout << "最 big 值: " << maximum(a, b) << endl; // usingcommon模板
double c = 3.14, d = 2.71;
cout << "最 big 值: " << maximum(c, d) << endl; // using普通function
const char* e = "apple";
const char* f = "banana";
cout << "最 big 值: " << maximum(e, f) << endl; // using特化模板
return 0;
}
2.4 many parameterfunction模板
function模板可以 has many 个模板parameter, 用于processing不同class型 parameter.
#include <iostream>
using namespace std;
// many parameterfunction模板
template <typename T1, typename T2, typename T3>
T3 sum(T1 a, T2 b) {
return static_cast<T3>(a + b);
}
// 具 has 默认模板parameter function模板 (C++11及以 on )
template <typename T1, typename T2 = T1>
T1 add(T1 a, T2 b) {
return a + b;
}
int main() {
// using many parameterfunction模板
int a = 10;
double b = 3.14;
cout << " and (int) : " << sum<int, double, int>(a, b) << endl;
cout << " and (double) : " << sum<int, double, double>(a, b) << endl;
// using具 has 默认模板parameter function模板
cout << "相加结果: " << add(a, b) << endl; // T2 默认 for int
cout << "相加结果: " << add<double>(a, b) << endl; // T1 指定 for double, T2 默认 for double
return 0;
}
3. class模板
3.1 class模板 定义
class模板 定义usingtemplate关键字, after 跟模板parameterlist, 然 after is class定义.
template <typename T>
class Vector {
private:
T* data;
int size;
int capacity;
public:
// constructfunction
Vector(int initialCapacity = 10) {
capacity = initialCapacity;
size = 0;
data = new T[capacity];
}
// 析构function
~Vector() {
delete[] data;
}
// 成员function
void push_back(const T& value) {
if (size >= capacity) {
// 扩容
capacity *= 2;
T* newData = new T[capacity];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
delete[] data;
data = newData;
}
data[size++] = value;
}
T& operator[](int index) {
return data[index];
}
int getSize() const {
return size;
}
};
3.2 class模板 using
usingclass模板时, 需要显式指定模板parameterclass型.
#include <iostream>
using namespace std;
template <typename T>
class Vector {
private:
T* data;
int size;
int capacity;
public:
// constructfunction
Vector(int initialCapacity = 10) {
capacity = initialCapacity;
size = 0;
data = new T[capacity];
}
// 析构function
~Vector() {
delete[] data;
}
// 成员function
void push_back(const T& value) {
if (size >= capacity) {
// 扩容
capacity *= 2;
T* newData = new T[capacity];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
delete[] data;
data = newData;
}
data[size++] = value;
}
T& operator[](int index) {
return data[index];
}
int getSize() const {
return size;
}
};
int main() {
// using int class型 Vector
Vector<int> intVector;
intVector.push_back(10);
intVector.push_back(20);
intVector.push_back(30);
cout << "intVector 元素: ";
for (int i = 0; i < intVector.getSize(); i++) {
cout << intVector[i] << " ";
}
cout << endl;
// using double class型 Vector
Vector<double> doubleVector;
doubleVector.push_back(1.1);
doubleVector.push_back(2.2);
doubleVector.push_back(3.3);
cout << "doubleVector 元素: ";
for (int i = 0; i < doubleVector.getSize(); i++) {
cout << doubleVector[i] << " ";
}
cout << endl;
// using string class型 Vector
Vector<string> stringVector;
stringVector.push_back("Hello");
stringVector.push_back("World");
cout << "stringVector 元素: ";
for (int i = 0; i < stringVector.getSize(); i++) {
cout << stringVector[i] << " ";
}
cout << endl;
return 0;
}
3.3 class模板 成员function
class模板 成员function可以 in class in 部定义, 也可以 in class out 部定义. in class out 部定义时, 需要using模板parameterlist.
#include <iostream>
using namespace std;
template <typename T>
class Stack {
private:
T* data;
int top;
int capacity;
public:
// constructfunction
Stack(int initialCapacity = 10);
// 析构function
~Stack();
// 成员function声明
void push(const T& value);
T pop();
T peek() const;
bool isEmpty() const;
int getSize() const;
};
// class模板 成员function in class out 部定义
template <typename T>
Stack<T>::Stack(int initialCapacity) {
capacity = initialCapacity;
data = new T[capacity];
top = -1;
}
template <typename T>
Stack<T>::~Stack() {
delete[] data;
}
template <typename T>
void Stack<T>::push(const T& value) {
if (top >= capacity - 1) {
// 扩容
capacity *= 2;
T* newData = new T[capacity];
for (int i = 0; i <= top; i++) {
newData[i] = data[i];
}
delete[] data;
data = newData;
}
data[++top] = value;
}
template <typename T>
T Stack<T>::pop() {
if (isEmpty()) {
throw "Stack is empty";
}
return data[top--];
}
template <typename T>
T Stack<T>::peek() const {
if (isEmpty()) {
throw "Stack is empty";
}
return data[top];
}
template <typename T>
bool Stack<T>::isEmpty() const {
return top == -1;
}
template <typename T>
int Stack<T>::getSize() const {
return top + 1;
}
int main() {
Stack<int> stack;
stack.push(10);
stack.push(20);
stack.push(30);
cout << "栈顶元素: " << stack.peek() << endl;
cout << "栈 big small : " << stack.getSize() << endl;
cout << "弹出元素: " << stack.pop() << endl;
cout << "弹出元素: " << stack.pop() << endl;
cout << "栈 big small : " << stack.getSize() << endl;
return 0;
}
3.4 class模板 特化
class模板可以被特化, for specificclass型providing专门 implementation.
#include <iostream>
#include <cstring>
using namespace std;
// commonclass模板
template <typename T>
class Compare {
public:
bool isEqual(T a, T b) {
return a == b;
}
};
// class模板特化 ( for const char* class型providing专门implementation)
template <>
class Compare<const char*> {
public:
bool isEqual(const char* a, const char* b) {
return strcmp(a, b) == 0;
}
};
int main() {
// usingcommonclass模板
Compare<int> intCompare;
cout << "10 == 20: " << (intCompare.isEqual(10, 20) ? "相etc." : "不相etc.") << endl;
cout << "10 == 10: " << (intCompare.isEqual(10, 10) ? "相etc." : "不相etc.") << endl;
// using特化 class模板
Compare<const char*> stringCompare;
cout << "\"Hello\" == \"World\": " << (stringCompare.isEqual("Hello", "World") ? "相etc." : "不相etc.") << endl;
cout << "\"Hello\" == \"Hello\": " << (stringCompare.isEqual("Hello", "Hello") ? "相etc." : "不相etc.") << endl;
return 0;
}
4. 模板 advanced features
4.1 可变parameter模板
可变parameter模板 (Variadic Templates) is C++11引入 features, 允许模板接受任意数量 模板parameter.
#include <iostream>
using namespace std;
// 递归终止function
void print() {
cout << "\n";
}
// 可变parameter模板function
template <typename T, typename... Args>
void print(T first, Args... rest) {
cout << first << " ";
print(rest...); // 递归调用
}
// 计算可变parameter and
template <typename T>
T sum(T value) {
return value;
}
template <typename T, typename... Args>
T sum(T first, Args... rest) {
return first + sum(rest...);
}
int main() {
// using可变parameter模板function打印 many 个值
cout << "打印 many 个值: ";
print(10, 3.14, "Hello", 'A');
// using可变parameter模板function计算 and
cout << " and : " << sum(1, 2, 3, 4, 5) << endl;
cout << " and : " << sum(1.1, 2.2, 3.3) << endl;
return 0;
}
4.2 模板 模板parameter
模板 模板parameter允许我们将模板serving as另一个模板 parameter.
#include <iostream>
#include <vector>
#include <list>
using namespace std;
// 模板 模板parameter
template <typename T, template <typename> class Container>
class MyContainer {
private:
Container<T> container;
public:
void add(const T& value) {
container.push_back(value);
}
void display() {
for (const auto& item : container) {
cout << item << " ";
}
cout << endl;
}
};
// for 了兼容标准librarycontainers (它们 has many 个模板parameter) , 需要调整模板parameter
template <typename T, template <typename...> class Container>
class GenericContainer {
private:
Container<T> container;
public:
void add(const T& value) {
container.push_back(value);
}
void display() {
for (const auto& item : container) {
cout << item << " ";
}
cout << endl;
}
};
int main() {
// using自定义containers
/*
MyContainer<int, vector> myVec;
myVec.add(10);
myVec.add(20);
myVec.add(30);
cout << "MyContainer with vector: ";
myVec.display();
*/
// usingcommoncontainers (兼容标准librarycontainers)
GenericContainer<int, vector> genericVec;
genericVec.add(10);
genericVec.add(20);
genericVec.add(30);
cout << "GenericContainer with vector: ";
genericVec.display();
GenericContainer<string, list> genericList;
genericList.add("Hello");
genericList.add("World");
cout << "GenericContainer with list: ";
genericList.display();
return 0;
}
4.3 class型别名 and 别名模板
C++11引入了using关键字来creationclass型别名, including别名模板.
#include <iostream>
#include <vector>
using namespace std;
// 传统 class型别名 (using typedef)
typedef vector<int> IntVector;
// C++11 class型别名 (using using)
using DoubleVector = vector<double>;
// 别名模板 (C++11及以 on )
template <typename T>
using Vec = vector<T>;
// 带 has 模板parameter 别名模板
template <typename T, typename Allocator = std::allocator<T>>
using MyVector = vector<T, Allocator>;
int main() {
// using传统 class型别名
IntVector iv;
iv.push_back(10);
iv.push_back(20);
cout << "IntVector size: " << iv.size() << endl;
// using C++11 class型别名
DoubleVector dv;
dv.push_back(1.1);
dv.push_back(2.2);
cout << "DoubleVector size: " << dv.size() << endl;
// using别名模板
Vec<int> v1;
v1.push_back(100);
v1.push_back(200);
cout << "Vec<int> size: " << v1.size() << endl;
Vec<string> v2;
v2.push_back("Hello");
v2.push_back("World");
cout << "Vec<string> size: " << v2.size() << endl;
return 0;
}
5. 模板 实践application
5.1 implementationcommon sortalgorithms
#include <iostream>
#include <vector>
using namespace std;
// common 冒泡sort模板function
template <typename T>
void bubbleSort(T arr[], int size) {
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// 交换元素
T temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
// common 打印array模板function
template <typename T>
void printArray(T arr[], int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
int main() {
// sort整型array
int intArr[] = {64, 34, 25, 12, 22, 11, 90};
int intSize = sizeof(intArr) / sizeof(intArr[0]);
cout << "sort before : ";
printArray(intArr, intSize);
bubbleSort(intArr, intSize);
cout << "sort after : ";
printArray(intArr, intSize);
// sort双精度浮点型array
double doubleArr[] = {64.5, 34.2, 25.7, 12.9, 22.1, 11.5, 90.8};
int doubleSize = sizeof(doubleArr) / sizeof(doubleArr[0]);
cout << "\nsort before : ";
printArray(doubleArr, doubleSize);
bubbleSort(doubleArr, doubleSize);
cout << "sort after : ";
printArray(doubleArr, doubleSize);
// sort字符array
char charArr[] = {'d', 'b', 'a', 'c', 'f', 'e'};
int charSize = sizeof(charArr) / sizeof(charArr[0]);
cout << "\nsort before : ";
printArray(charArr, charSize);
bubbleSort(charArr, charSize);
cout << "sort after : ";
printArray(charArr, charSize);
return 0;
}
5.2 implementationcommon 智能指针
#include <iostream>
using namespace std;
// common 智能指针模板class
template <typename T>
class SmartPointer {
private:
T* ptr;
public:
// constructfunction
explicit SmartPointer(T* p = nullptr) : ptr(p) {
cout << "constructfunction调用" << endl;
}
// 析构function
~SmartPointer() {
cout << "析构function调用" << endl;
delete ptr;
}
// 拷贝constructfunction (禁用)
SmartPointer(const SmartPointer&) = delete;
// 拷贝赋值运算符 (禁用)
SmartPointer& operator=(const SmartPointer&) = delete;
// moveconstructfunction (C++11及以 on )
SmartPointer(SmartPointer&& other) noexcept : ptr(other.ptr) {
cout << "moveconstructfunction调用" << endl;
other.ptr = nullptr;
}
// move赋值运算符 (C++11及以 on )
SmartPointer& operator=(SmartPointer&& other) noexcept {
cout << "move赋值运算符调用" << endl;
if (this != &other) {
delete ptr;
ptr = other.ptr;
other.ptr = nullptr;
}
return *this;
}
// 重载解引用运算符
T& operator*() const {
return *ptr;
}
// 重载箭头运算符
T* operator->() const {
return ptr;
}
// check指针 is 否 for 空
bool isNull() const {
return ptr == nullptr;
}
};
class Test {
public:
Test() {
cout << "Testconstructfunction调用" << endl;
}
~Test() {
cout << "Test析构function调用" << endl;
}
void print() {
cout << "Test::print()调用" << endl;
}
};
int main() {
// using智能指针management动态分配 object
cout << "=== creation智能指针 ===" << endl;
SmartPointer<Test> sp1(new Test());
sp1->print();
(*sp1).print();
// usingmoveconstructfunction
cout << "\n=== usingmoveconstructfunction ===" << endl;
SmartPointer<Test> sp2 = move(sp1);
cout << "sp1 is 否 for 空: " << (sp1.isNull() ? " is " : "否") << endl;
sp2->print();
// usingmove赋值运算符
cout << "\n=== usingmove赋值运算符 ===" << endl;
SmartPointer<Test> sp3;
sp3 = move(sp2);
cout << "sp2 is 否 for 空: " << (sp2.isNull() ? " is " : "否") << endl;
sp3->print();
cout << "\n=== 程序结束 ===" << endl;
return 0;
}
实践case: implementationcommon 线性搜索algorithms
using模板implementation一个common 线性搜索algorithms, 可以搜索不同class型 array and containers.
requirementsanalysis
- implementation一个common 线性搜索function, 可以搜索不同class型 元素
- supportarray and STLcontainers 搜索
- 返回找 to 元素 index or iterators
- such as果元素未找 to , 返回特殊值 or end()iterators
referencecode
#include <iostream>
#include <vector>
#include <list>
using namespace std;
// for arrayimplementation 线性搜索模板function
template <typename T>
int linearSearch(const T arr[], int size, const T& target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i; // 返回找 to 元素 index
}
}
return -1; // 未找 to , 返回-1
}
// for STLcontainersimplementation 线性搜索模板function
template <typename Container, typename T>
auto linearSearch(const Container& container, const T& target) -> decltype(container.begin()) {
for (auto it = container.begin(); it != container.end(); ++it) {
if (*it == target) {
return it; // 返回找 to 元素 iterators
}
}
return container.end(); // 未找 to , 返回end()iterators
}
int main() {
// 搜索array
int intArr[] = {10, 20, 30, 40, 50};
int intSize = sizeof(intArr) / sizeof(intArr[0]);
int intTarget = 30;
int intIndex = linearSearch(intArr, intSize, intTarget);
if (intIndex != -1) {
cout << "找 to 整数 " << intTarget << ", index: " << intIndex << endl;
} else {
cout << "未找 to 整数 " << intTarget << endl;
}
// 搜索vector
vector<string> strVec = {"apple", "banana", "cherry", "date"};
string strTarget = "cherry";
auto strIt = linearSearch(strVec, strTarget);
if (strIt != strVec.end()) {
cout << "找 to string " << strTarget << ", 位置: " << distance(strVec.begin(), strIt) << endl;
} else {
cout << "未找 to string " << strTarget << endl;
}
// 搜索list
list<double> doubleList = {1.1, 2.2, 3.3, 4.4, 5.5};
double doubleTarget = 4.4;
auto doubleIt = linearSearch(doubleList, doubleTarget);
if (doubleIt != doubleList.end()) {
cout << "找 to 双精度数 " << doubleTarget << endl;
} else {
cout << "未找 to 双精度数 " << doubleTarget << endl;
}
return 0;
}
互动练习
练习1: implementation一个common Swapfunction, 用于交换两个不同class型 值.
要求:
- usingfunction模板implementation
- support不同class型 parameter
- in 主functionintest交换整数, 浮点数 and string
练习2: implementation一个common Queueclass模板.
要求:
- using动态arrayimplementation
- support入队 (enqueue) , 出队 (dequeue) operation
- support获取队首元素 (front) and 队尾元素 (back)
- supportcheckqueue is 否 for 空 (isEmpty) and 获取queue big small (size)
- in 主functionintest不同class型 queue
练习3: implementation一个common Pairclass模板, 用于store一 for 不同class型 值.
要求:
- using两个模板parameter
- providingconstructfunction and 访问器method
- implementation比较运算符 (==, !=)
- in 主functionintest不同class型 Pair