背景:例如要比较两个 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;

# 模板与继承

  • 普通类可从类模板实例继承。
  • 类模板可从普通类继承。
  • 类模板可以继承类模板。
  • 普通类不能从类模板继承。
更新于