C++模板:函数模板、类模板
C++ 模板是一种强大的特性,它允许程序员编写泛型代码,即在编写代码时不指定具体的数据类型,而是在使用模板时再确定类型。以下是关于C++模板的详细介绍:
一、函数模板
函数模板是一种通用的函数定义,可以用于处理不同类型的数据,只要这些类型支持模板函数内部操作所需的操作符或成员函数。
函数模板的定义以关键字template开始,后面跟着一个或多个模板参数,这些参数通常是类型参数,用尖括号<>括起来。
下面是一个简单的函数模板,用于交换两个变量的值:
template <typename T> void swap(T& a, T& b) { T temp = a; a = b; b = temp; }
在这个例子中,typename T 声明了一个类型参数T,函数swap可以用于交换任何类型T的两个变量的值,只要类型T支持赋值操作。
使用函数模板时,编译器会根据传入的实际参数类型自动生成相应的函数实例。例如:
int main() { int num1 = 5, num2 = 10; swap(num1, num2); double num3 = 3.14, num4 = 2.71; swap(num3, num4); return 0; }
当调用swap(num1, num2)时,编译器会生成一个swap函数的实例,其中T被替换为int类型;当调用swap(num3, num4)时,T被替换为double类型。
二、类模板
类模板与函数模板类似,但它是用于创建泛型类的。类模板可以包含成员变量、成员函数等,这些成员的类型可以是模板参数类型。
以下是一个简单的类模板示例,用于表示一个动态大小的数组:
template <typename T, int size> class Array { public: Array() {} T& operator[](int index) { return data[index]; } private: T data[size]; };
在这个类模板中,有两个模板参数:typename T 表示数组中元素的类型,int size 表示数组的大小。
使用类模板时,需要指定模板参数。例如:
int main() { Array<int, 5> intArray; intArray[0]=1; Array<double, 3> doubleArray; doubleArray[1] = 3.14; return 0; }
这里创建了两个不同类型的Array类实例:intArray是一个包含5个int元素的数组,doubleArray是一个包含3个double元素的数组。
三、模板的特化
模板特化是指为特定的模板参数类型提供专门的模板实现。当使用这些特定类型时,编译器会优先使用特化的模板版本,而不是通用的模板版本。
假设我们有一个函数模板用于比较两个数的大小:
template <typename T> bool compare(T a, T b) { return a < b; }
对于const char*类型(C - 风格字符串),上面的通用模板实现可能不符合预期,因为直接比较指针的值并不能比较字符串的实际内容。所以我们可以对const char*类型进行特化:
template <> bool compare<const char*>(const char* a, const char* b) { return strcmp(a, b)<0; }
在这个特化版本中,我们使用strcmp函数来比较两个C - 风格字符串的实际内容。
四、模板的优势
1. 代码复用
通过编写通用的模板代码,可以避免为不同类型编写重复的函数或类。例如,不需要为int、double、float等类型分别编写交换函数,一个函数模板就可以满足需求。
2. 类型安全
模板是类型安全的,因为编译器会根据实际使用的类型生成相应的代码。如果类型不支持模板内部所需的操作,编译器会在编译时检测到错误。
3. 灵活性和可扩展性
可以方便地添加新的类型支持,只需要满足模板内部操作的要求即可。并且可以通过模板特化来处理特定类型的特殊情况。