目录
1.函数模板:构建通用函数的基石
1.1函数模板的定义与语法
函数模板是C++泛型编程的基础之一,它允许我们定义一个通用的函数框架,能够处理不同数据类型的操作。其定义方式需要借助template关键字,后面紧跟尖括号<>,在尖括号内声明类型参数。
例如,下面是一个简单的函数模板,用于比较两个值并返回较大的那个:
template <typename T>
T max(T a, T b) {
return a > b? a : b;
}
/*
在这个例子中,template <typename T>声明了这是一个函数模板,其中typename表明T是一个类型参数,你也可以使用class关键字来代替typename,效果是一样的。在函数体中,T就如同一个占位符,可以代表任意数据类型。当调用这个函数模板时,编译器会根据传入的实际参数类型,自动生成对应的具体函数 。
*/
1.2函数模板的使用方式
函数模板的使用方式主要有两种:自动类型推导和显式指定类型。
1.2.1自动类型推导
自动类型推导是最常用的方式,编译器会根据调用函数时传入的参数类型,自动确定模板参数的具体类型。
例如:
int num1 = 5, num2 = 10;
int result1 = max(num1, num2);
/*
在这个调用中,编译器通过num1和num2的类型(均为int),自动推导出T为int,从而生成一个针对int类型的max函数。
*/
1.2.2显式指定类型
显式指定类型则是在调用函数模板时,明确写出模板参数的具体类型。
例如:
double num3 = 3.14, num4 = 2.71;
double result2 = max<double>(num3, num4);
/*
这里通过<double>显式指定了T的类型为double,编译器会据此生成处理double类型的max函数。显式指定类型在某些情况下非常有用,比如当编译器无法自动推导类型,或者需要明确指定使用某种类型时 。
*/
1.3函数模板与函数重载
当函数模板与普通函数同时存在,且都能匹配函数调用时,编译器遵循一定的规则来选择合适的函数。
一般情况下,如果有一个普通函数与函数模板提供的功能相同,且函数调用时参数类型与普通函数的参数类型完全匹配,那么编译器会优先选择普通函数。例如:
int max(int a, int b)
{
return a > b? a : b;
}
template <typename T>
T max(T a, T b)
{
return a > b? a : b;
}
int main()
{
int num1 = 5, num2 = 10;
int result = max(num1, num2);
return 0;
}
/*
在这个例子中,max(num1, num2)调用的是普通函数int max(int a, int b),因为它与函数调用的参数类型完全匹配,并且在这种情况下,普通函数具有更高的优先级 。
如果没有完全匹配的普通函数,或者显式指定使用函数模板(例如max<int>(num1, num2)),编译器才会考虑函数模板,并根据参数类型生成相应的具体函数。此外,如果存在多个函数模板都能匹配调用,编译器会选择最特化(即最具体)的那个函数模板 。
*/
1.4函数模板的特化
函数模板特化是指针对特定的数据类型,为函数模板提供专门的实现。有时,对于某些特殊类型,通用的函数模板实现可能并不合适,这时就需要进行特化处理。
例如,对于比较两个指针的大小,直接比较指针的值(地址)可能没有实际意义,我们可能希望比较指针所指向的内容。可以对前面的max函数模板进行特化:
template <typename T>
T max(T a, T b)
{
return a > b? a : b;
}
template <>
const char* max<const char*>(const char* a, const char* b)
{
return strcmp(a, b) > 0? a : b;
}
/*
在这个特化版本中,template <>表示这是一个特化的函数模板,尖括号内为空,表示对所有模板参数进行特化(这里只有一个模板参数T)。max<const char*>(const char* a, const char* b)明确指定了针对const char*类型的特化实现,使用strcmp函数来比较字符串的内容 。
通过这种方式,当调用max函数并传入const char*类型的参数时,编译器会优先使用特化版本的函数,而不是通用的函数模板,从而满足特定类型的特殊需求 。
*/
2.类模板:创建通用类的利器
2.1类模板的定义与语法
类模板允