背景:例如要比较两个 int/double/char 的大小,避免定义三个函数 / 重载函数造成麻烦。
# 函数模板
# 语法
template <typename T> // 模板前缀,<class T > 也可,typename 理解为一种表示数据类型的数据类型 | |
returnType functionName (T para1, ...) | |
{ | |
//Function Body | |
} | |
template <typename T, typename S> // 多个类型参数 | |
returnType functionName (T para1, S para2...) {} //C++14 可自动推导返回值类型 |
实例:
#include <iostream> | |
using namespace std; | |
template <typename T> | |
T add(T x, T y) | |
{ | |
return x + y; | |
} | |
int main() | |
{ | |
cout << add(2, 3) << endl; | |
add(2.33, 233); // 报错,编译器会实例化 add (double, int), 但并没有 add (T, S) 模板。 | |
return 0; | |
} |
实例 2:
#include <iostream> | |
using namespace std; | |
template <typename T, typename Q> | |
T add(T x, Q y) //C++14 这里返回值类型可以写 auto 比较舒服 | |
{ | |
return x + y; | |
} | |
int main() | |
{ | |
cout << add(2.33, 3) << endl; // 5.33 | |
cout << add(2, 3.22) << endl; // 5 | |
return 0; | |
} |
# 实例化
编译器遇到模板定义时并不会立即产生代码,确定模板实参之后,编译器才会生成 对应函数实际代码。
模板多态是编译时多态。
显示实例化:
template <typename T> | |
void f(T x) | |
{ | |
//... | |
} | |
template void f<double>(double); | |
template void f<>(char); | |
template void f(int); |
隐式实例化:(接上段)
f<double>(1); //double | |
f<>('a'); //char | |
f(7); //int | |
void (*ptr)(std::string) = f; // 声明函数指针并实例化 |
ex: 关于字符串字面量的大小比较,实际上是比较地址高低。 例如:
template <typename T> | |
T max(T x, T y) // 与 algorithm 中 max 撞名注意 qwq | |
{ | |
return x > y ? x : y; | |
} | |
---------------- | |
max("owo", "qwq"); //owo 高地址 | |
max("qwq", "owo"); //owo 复用刚才的字面量 | |
----另一个程序---- | |
max("qwq", "owo"); //qwq | |
max("owo", "qwq"); //qwq | |
----------------//string 类型才是 strcmp | |
max("owo"s, "qwq"s); //qwq |
# 泛型函数
- 确定函数处理哪些数据。
- 相关数据类型转化为泛型。
void selectSort(double list[], const int size); | |
-> | |
void selectSort(T list[], const int size); |
# 类模板
# 语法
实例 - 栈:
template<typename T> | |
class Stack | |
{ | |
public: | |
Stack(); | |
bool empty(); | |
T peek(); | |
T push(T value); | |
T pop(); | |
int getSize(); | |
private: | |
T elements[100]; | |
int size; | |
}; | |
// 函数定义时也要加上相应前缀,例如: | |
template <typename T> | |
bool Stack<T>::empty() | |
{ | |
return size == 0; | |
} |
# 实例化
显式实例化:
template class Stack<int>; |
隐式实例化:
Stack<char> charStack; // 先实例化类,再定义 charStack 对象。 | |
Stack<int> intStack; |
# 类模板的默认类型
跟参数默认值一样的东西:(函数模板不能用)
template <typename T = int> | |
class Stack{ | |
//... | |
} | |
Stack<> stack; |
# 非类型参数
在模板前缀使用非类型参数
实例化模板时, 非类型实参应该是对象。
template<typename T, int capacity> | |
class Stack | |
{ | |
public: | |
//... | |
private: | |
T elements[capacity]; | |
int size; | |
}; | |
Stack<char, 100> charStack; |
# 模板与继承
- 普通类可从类模板实例继承。
- 类模板可从普通类继承。
- 类模板可以继承类模板。
- 普通类不能从类模板继承。