模板 与 泛型编程
- 模板是泛型编程的基础,泛型编程即以一种 独立于任何特定类型 的方式编写代码。
- 模板是创建 泛型类或函数 的蓝图或公式。
- 泛型编程关注的是算法,旨在编写独立于数据类型的代码
标准模板库 STL Standard Template Library
- STL 提供了一组表示 容器、迭代器、函数对象和算法 的模板。
- 容器 是一个与数组类似的单元,可以存储若干个值。STL容器是同质的,即存储的值的类型相同;
- 迭代器 能够用来遍历容器的对象,与能够遍历数组的指针类似,是广义指针;
- 算法 是完成特定任务(如对数组进行排序或在链表中查找特定值)的处方;
- 函数对象 是类似于函数的对象,可以是类对象或函数指针(包括函数名,因为函数名被用作指针)
函数模板 & 模板函数
1.函数模板
函数模板的重点是模板。表示的是一个模板,专门用来生产函数。
template <typename T>
void fun(T a)
{
// 函数主体
}
在运用的时候,可以 显式(explicitly)生产模板函数
fun <int> 、fun <double> 、fun <Shape*> ……。
也可以在使用的过程中 由编译器进行模板参数推导隐式(implicitly)生成。
fun(6); // 隐式生成fun <int>
fun(8.9); // 隐式生成fun <double>
fun(‘a’); // 隐式生成fun <char>
Shape* ps = new Circle;
fun(ps); // 隐式生成fun <Shape*>
2.模板函数
模板函数的重点是函数。表示的是由一个模板生成而来的函数。
上面由 函数模板 显式或者隐式 生成的函数都是 模板函数。
3.实例
Max 函数模板
#include <iostream>
using namespace std;
// 定义函数模板
template<typename T>
inline T const &Max(T const &a, T const &b) {
return a < b ? b : a;
}
// 函数使用引用为了不必多余赋值,直接凭地址取值,加快速度
// const是编程范式,对于值不会改变的参数,const可以加快速度
int main() {
// 三种不同类型的 模板函数
int i = 39;
int j = 20;
cout << "Max(i, j): " << Max(i, j) << endl;
double f1 = 13.5;
double f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
string s1 = "Hello";
string s2 = "World";
cout << "Max(s1, s2): " << Max(s1, s2) << endl;
return 0;
}
Max(i, j): 39
Max(f1, f2): 20.7
Max(s1, s2): World
类模板 & 模板类
1.类模板
类模板的重点是模板。表示的是一个模板,专门用于产生类。
template <typename T>
class Vector
{
// 类主体
};
使用 Vector模板 可以产生很多的模板类
Vector <int> 、Vector <char> 、Vector <Vector <int>> 、Vector <Shape*>
2.模板类
模板类的重点是类。表示的是由一个模板生成而来的类。
上面的 Vector <int> 、Vector <char> 、…… 全是模板类。
3.实例
Stack 类模板
#include <iostream>
#include <vector>
using namespace std;
// Stack 类模板
template<class T> // typename和class都可以
class Stack {
private:
vector<T> elems; // 元素
public:
// 下面的方法都基于 vector 数据结构
void push(T const &); // 入栈
void pop(); // 出栈
T top() const; // 返回栈顶元素
// const 类型的类对象不能访问 非const 的类方法
// 所以这里的类方法添加了const
bool empty() const { // 如果为空则返回真。
return elems.empty();
}
};
// 定义函数的时候要声明 泛型
template<class T>
void Stack<T>::push(T const &elem) {
elems.push_back(elem); // 在末尾添加元素
}
template<class T>
void Stack<T>::pop() {
if (elems.empty()) {
throw out_of_range("Stack<>::pop(): empty stack");
}
elems.pop_back(); // 删除最后一个元素
}
template<class T>
T Stack<T>::top() const {
if (elems.empty()) {
throw out_of_range("Stack<>::top(): empty stack"); // 异常信息,存在ex.what()中
}
return elems.back(); // 返回最后一个元素
}
int main() {
try {
Stack<int> intStack; // int 类型的栈
Stack<string> stringStack; // string 类型的栈
// 操作 int 类型的栈
intStack.push(7);
cout << intStack.top() << endl;
// 操作 string 类型的栈
stringStack.push("hello");
cout << stringStack.top() << std::endl;
stringStack.pop();
stringStack.pop();
} catch (exception const &ex) {
cerr << "Exception: " << ex.what() << endl;
return -1;
}
}
7
hello
Exception: Stack<>::pop(): empty stack