C++模板编程
C++函数模板
函数模板的概念
函数模板是用于生成函数的模板。在编译阶段,编译器会根据函数模板的使用情况创建出函数名相同,参数类型由编译器判断的若干函数。
通过函数模板创建的函数体相同,不同点在于参数类型。
函数模板的使用
每当在一个编译单元(经过预处理的.cpp文件)中使用了函数模板,则必须在该单元中定义一个与函数模板相对应的函数。
因此,建议在头文件中对函数模板进行声明定义。
函数模板的声明:
template <typename T> // 其中T表示任意类型,参数类型和返回值都可以指定为T
返回类型 函数名(参数列表);
{
函数体
}
示例代码
- 新建一个头文件
template.h
,文件内容如下:#pragma once #ifndef _COMPARE_H #define _COMPARE_H template<typename T> bool isEqual(T i, T j); template<typename T> bool isEqual(T i, T j) { return i == j; } #endif // !_COMPARE_H
- 新建
main.cpp
,在main.cpp
中使用函数模板:#include <iostream> using namespace std; #include "compare.h" int main(int argc, char *argv[]) { cout << isEqual(1, 1) << endl; cout << isEqual(22, 1) << endl; cout << isEqual(0.1, 0.2) << endl; cout << isEqual(1.0f, 1.0f) << endl; cout << isEqual("TTT", "TTT") << endl; return 0; }
- 编译运行
main.cpp
,效果如下1 0 0 1 1
函数模板的特化
函数模板的特化是指在实例化模板时,对特定类型的实参进行特殊处理,即当实参为特定类型时,使用该类型的函数体。
特化需要为函数模板添加新的定义,方式如下
template <>
返回类型 函数名<具体类型>(参数列表)
{
函数体
}
示例代码
- 修改
main.cpp
文件,修改成如下代码:#include <iostream> using namespace std; #include "compare.h" int main(int argc, char *argv[]) { char str1[20] = "Hello"; char str2[20] = "Hello"; if (isEqual(str1, str2)) { cout << "Equal" << endl; } else { cout << "Not Equal" << endl; } return 0; }
- 编译运行
main.cpp
,效果如下
为什么两个明明是相同类型和字符数相同的字符串,却返回了Not Equal
Not Equal
呢?
- 原来是
isEqual
函数模板在比较字符串时,默认使用==
运算符,而==
运算符比较的是字符串的地址,所以返回了Not Equal
。 - 字符串内容比较,应该使用
strcmp函数
。
修改
compare.h
文件,添加如下代码:template <> bool isEqual<char*>(char* s1, char* s2) { return (strcmp(s1, s2) == 0); }
编译运行
main.cpp
,效果如下Equal
C++类模板
类模板的概念
类模板是用于生成类的模板。在编译阶段,编译器会根据类模板的使用情况创建出仅有部分成员的数据类型和部分成员函数参数类型不同,其他完全相同的若干类。
通过类模板,可以尝试写出用于存放不同类型数据的容器。
类模板的使用
类模板的声明
类模板的声明和函数模板的声明类似,只是类模板的声明中包含了一个模板参数列表,用于指定模板参数
类模板的声明如下,其中T代表任意类型,由用户指定
template <typename T,...>
class 类名
{
类成员
}
类模板的成员函数定义如下,一般类模板也应该写在头文件中
template <typename T,...>
返回类型 类名<T,...>::函数名(参数列表)
{
函数体
}
实例代码
编写通用数组类,创建
MyArray.h
头文件,添加如下代码:#pragma once #ifndef _MYARRAY_H #define _MYARRAY_H template <typename T> class MyArray { private: T data[20]; int len; public: MyArray(); T indexof(int index); void addValue(T value); }; template <typename T> MyArray<T>::MyArray() : len(0) { } template <typename T> T MyArray<T>::indexof(int index) { return data[index]; } template <typename T> void MyArray<T>::addValue(T value) { data[len] = value; len++; } #endif // !_MYARRAY_H
测试整形数组,创建
main.cpp
源文件,添加如下代码:#include <iostream> using namespace std; #include "MyArray.h" int main(int argc, char *argv[]) { MyArray<int> arr; for (int i = 0; i < 10; ++i) { arr.addValue(i); } for (int j = 0; j < 10; ++j) { cout << arr.indexof(j) << endl; } return 0; }
编译并运行程序,输出结果如下:
0 1 2 3 4 5 6 7 8 9
测试浮点型数组,修改
main.cpp
源文件,代码如下:#include <iostream> using namespace std; #include "MyArray.h" int main(int argc, char *argv[]) { MyArray<double> arr; for (int i = 0; i < 10; ++i) { arr.addValue(i+.112f); } for (int j = 0; j < 10; ++j) { cout << arr.indexof(j) << endl; } return 0; }
编译并运行程序,输出结果如下:
0.112 1.112 2.112 3.112 4.112 5.112 6.112 7.112 8.112 9.112
类模板的特化和偏特化
类模板的特化
类模板的特化是指在实例化类模板时,对特定类型的泛型进行特殊处理,即用户指定特定类型的类模板时,通过特化过类模板生成的类可能于其他的类由完全不同的结构。
特化类模板需要对整个类模板进行声明定义:
template <>
class 类名<指定类型, 指定类型, ...>
{
类成员
}
示例代码
- 修改
MyArray.h
头文件,添加如下代码:template <> class MyArray<double> { public: MyArray(); }; MyArray<double>::MyArray() { cout << "MyArray<double>::MyArray()" << endl; }
- 修改
main.cpp
源文件,添加如下代码:
其中的main函数
内容如下MyArray<double> arr; return 0;
- 编译并运行程序,输出结果如下:
MyArray<double>::MyArray()
类模板的偏特化
偏特化与特化相似,但是偏特化只对类模板的部分参数进行特化,而不是对整个类模板进行特化。
偏特化模板是需要对整个类模板进行声明定义:
template <typename T, 不需要特化的泛型, ...>
class 类名<T, 不需要特化的泛型, ...>
{
类成员
}
示例代码
新增文件
pair.h
,内容如下:#pragma once #ifndef _PAIR_H #define _PAIR_H #include <iostream> using namespace std; template<typename T1, typename T2> class Pair { private: T1 first; T2 second; public: Pair(); }; template <typename T1, typename T2> Pair<T1, T2>::Pair() { cout << "Pair<T1, T2>::Pair()" << endl; } template <typename T2> class Pair<char, T2> { public: Pair(); }; template <typename T2> Pair<char, T2>::Pair() { cout << "Pair<char, T2>::Pair()" << endl; } #endif // !_PAIR_H
main.cpp
文件内容如下:#include <iostream> using namespace std; #include "pair.h" int main(int argc, char *argv[]) { Pair<char, int> p1; Pair<int, char> p2; return 0; }
编译并运行程序,输出结果如下:
Pair<char, T2>::Pair() Pair<T1, T2>::Pair()