系列目录
上一篇:白骑士的C++教学进阶篇 2.2 面向对象编程(OOP)
模板是C++中一个强大的特性,允许编写通用的代码,提高代码的重用性和灵活性。模板分为函数模板和类模板,还包括模板特化。本篇博客将详细介绍这些内容,帮助您深入理解和应用模板编程。
函数模板
函数模板允许定义通用的函数,不依赖具体的数据类型。通过参数化类型,函数模板可以用于不同类型的参数。
函数模板的定义与使用
定义一个函数模板使用 ‘template‘ 关键字和模板参数列表。例如,定义一个通用的交换函数:
template <typename T>
void swap(T& a, T& b) {T temp = a;a = b;b = temp;
}
在这个例子中,‘T‘ 是一个模板参数,可以代表任意类型。使用函数模板交换两个整数和两个字符串,代码如下:
int main() {int x = 10, y = 20;swap(x, y);std::cout << "x: " << x << ", y: " << y << std::endl;std::string str1 = "Hello", str2 = "World";swap(str1, str2);std::cout << "str1: " << str1 << ", str2: " << str2 << std::endl;return 0;
}
在上面的代码中,模板参数 ‘T‘ 分别被推导为 ‘int‘ 和 ‘std::string‘,实现了通用的交换功能。
多个模板参数
函数模板可以有多个模板参数。例如,定义一个比较函数,返回较大的值:
template <typename T1, typename T2>auto max(T1 a, T2 b) -> decltype(a > b ? a : b) {return a > b ? a : b;
}
使用该模板函数比较不同类型的值,例如:
int main() {int a = 10;double b = 20.5;std::cout << "Max: " << max(a, b) << std::endl;char c = 'A';std::cout << "Max: " << max(a, c) << std::endl;return 0;
}
在上面的代码中,模板参数 ‘T1‘ 和 ‘T2‘ 分别被推导为 ‘int‘ 和 ‘double‘,实现了通用的比较功能。
类模板
类模板允许定义通用的类,不依赖具体的数据类型。通过参数化类型,类模板可以用于不同类型的成员变量和方法。
类模板的定义与使用
定义一个类模板使用 ‘template‘ 关键字和模板参数列表。例如,定义一个通用的数组类:
template <typename T>class Array {
private:T* data;int size;public:Array(int s) : size(s) {data = new T[size];}~Array() {delete[] data;}T& operator[](int index) {return data[index];}int getSize() const {return size;}
};
在这个例子中,‘T‘ 是一个模板参数,可以代表任意类型。使用类模板创建整数数组和字符串数组,例如:
int main() {Array<int> intArray(5);for (int i = 0; i < intArray.getSize(); i++) {intArray[i] = i * 10;}for (int i = 0; i < intArray.getSize(); i++) {std::cout << intArray[i] << std::endl;}Array<std::string> strArray(3);strArray[0] = "Hello";strArray[1] = "World";strArray[2] = "C++";for (int i = 0; i < strArray.getSize(); i++) {std::cout << strArray[i] << std::endl;}return 0;
}
在上面的代码中,模板参数 ‘T‘ 分别被推导为 ‘int‘ 和 ‘std::string‘,实现了通用的数组类。
多个模板参数
类模板可以有多个模板参数。例如,定义一个键值对类:
template <typename K, typename V>class KeyValuePair {
private:K key;V value;public:KeyValuePair(K k, V v) : key(k), value(v) {}K getKey() const {return key;}V getValue() const {return value;}
};
使用该类模板创建不同类型的键值对,例如:
int main() {KeyValuePair<int, std::string> intStrPair(1, "one");std::cout << "Key: " << intStrPair.getKey() << ", Value: " << intStrPair.getValue() << std::endl;KeyValuePair<std::string, double> strDoublePair("PI", 3.14);std::cout << "Key: " << strDoublePair.getKey() << ", Value: " << strDoublePair.getValue() << std::endl;return 0;
}
在上面的代码中,模板参数 ‘K‘ 和 ‘V‘ 分别被推导为 ‘int‘ 和 ‘std::string‘,实现了通用的键值对类。
模板特化
模板特化允许为特定的数据类型提供特殊的实现。当通用的模板代码不能满足特定类型的需求时,使用模板特化可以提供优化或特定功能的实现。
全特化
全特化是为特定类型提供完全不同的实现。例如,定义一个打印模板函数,并为 ‘char*‘ 类型提供特化:
template <typename T>void print(T value) {std::cout << "Generic print: " << value << std::endl;
}template <>void print<char*>(char* value) {std::cout << "Specialized print: " << value << std::endl;
}
使用模板函数打印不同类型的值,例如:
int main() {print(42);print(3.14);print("Hello, world!");return 0;
}
在上面的代码中,‘print‘ 模板函数为 ‘char*‘ 类型提供了特化,实现了不同的打印功能。
偏特化
偏特化是为模板的某些参数提供特定的实现,而其他参数仍然使用通用模板。例如,定义一个通用的数组类模板,并为指针类型提供偏特化:
template <typename T>class Array {
private:T* data;int size;public:Array(int s) : size(s) {data = new T[size];}~Array() {delete[] data;}T& operator[](int index) {return data[index];}int getSize() const {return size;}
};// 为指针类型提供偏特化
template <typename T>class Array<T*> {
private:T** data;int size;public:Array(int s) : size(s) {data = new T*[size];for (int i = 0; i < size; i++) {data[i] = nullptr;}}~Array() {for (int i = 0; i < size; i++) {delete data[i];}delete[] data;}T*& operator[](int index) {return data[index];}int getSize() const {return size;}
};
使用该模板类创建指针数组,例如:
int main() {Array<int*> ptrArray(3);for (int i = 0; i < ptrArray.getSize(); i++) {ptrArray[i] = new int(i * 10);}for (int i = 0; i < ptrArray.getSize(); i++) {std::cout << *ptrArray[i] << std::endl;}return 0;
}
在上面的代码中,模板类 ‘Array‘ 为指针类型提供了偏特化,实现了不同的内存管理。
总结
模板是C++中一个强大的特性,通过函数模板、类模板和模板特化,程序员可以编写通用、高效的代码,提高代码的重用性和灵活性。理解并熟练掌握模板编程,将大大提高您的编程能力和效率。希望通过本篇博客的介绍,您能更好地理解和应用C++模板,为编写复杂和高效的C++程序打下坚实的基础。
下一篇:白骑士的C++教学进阶篇 2.4 标准模板库(STL)