模板,泛型编程
1)泛型编程
对于一个加法函数,要是参数类型不同,就必须把每种类型的函数都重载出来
int Add(int left, int right)
{
return left + right;
}
double Add(double left, double right)
{
return left + right;
}
char Add(char left, char right)
{
return left + right;
}
全部重载的缺陷:
1.代码复用性较低
2.不好维护
3.不能将所有类型重载(自定义类型)
我们看到这几段代码的框架都一样,这时候就需要一种泛型编程,帮我们实现每种类型的函数。泛型编程:编写与类型和数据结构无关的通用代码,是代码复用的一种手段,模板是泛型编程的基础
2)函数模板
template< class T>或者template< typename T>
概念: 函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
template<class T> 也可以是template<typename T>,但不能用struct代替class,struct默认为public,而class为private
T Add(T left, T right)
{
return left+right;
}
int main()
{
printf("%d\n", Add(1, 2));
printf("%d\n", Add<int>(1,2)); //显示实例化:告诉编译器以什么参数类型进行计算
printf("%lf\n", Add(1.0, 2.0));
printf("%d\n", Add(1, 2.0)); //这行代码报错,编译器无法推演出类型到底是int还是double,这时需要修改模板template<class T1,class T2>,类中的参数列表和返回这也应该修改
return 0;
}
隐式实例化: Add(1,2);没有明确指定模板参数列表T的实际类型
1.编译器先根据传参进行推演,根据推演结果确定挡模板T的类型
2.推演的类型不可确定则报错
显示实例化: Add(1,2);明确了模板参数列表中T的实际类型
1.如果发现参数列表类型不匹配,会进行隐式转化
2.转化成功:编译通过 失败:编译报错
当int Add(int left,int right);被显示定义出来,用Add显示实例化时,不会调用模板生成一份代码,而是直接调用定义出来的
3)类模板
直接上代码:
template<class T>
class Seqlist
{
public:
Seqlist(int capacity = 5) //构造
:_base(new T[capacity])
, _capacity(capacity)
, _size(0)
{}
~Seqlist(); //析构函数在类外定义
void SeqPush(const T data) //尾插
{
_base[_size] = data;
_size++;
}
private:
T* _base;
int _size;
int _capacity;
};
template<class T>
Seqlist<T>::~Seqlist() //在类外实现定义的函数,需要加模板参数列表
{
if (_base)
{
delete[] _base;
_capacity = 0;
_size = 0;
}
}
int main()
{
Seqlist<int> s1(10);
Seqlist<double>s2(10);
s1.SeqPush(1);
s2.SeqPush(1.0);
return 0;
}
在汇编中可以看到:
编译器对不同的类型生成不同的函数
需要注意的点:
1.函数在类外定义时,必须加模板参数列表,否则报错。例:Seqlist< T >::~Seqlist()定义前加template< class T >
2.类模板实例化时,必须写成Seqlist< type > 这才是类型,实例化结果是真正的类。例:Seqlist s1(10);
3.编译器在处理模板类时,会分两次编译和普通类型的类不同。
4.类模板中的成员函数全都是函数模板
4)用模板实现顺序表
5)STL简介
什么是STL?
STL(standard template liarbry—标准模板库),是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构和算法的软件框架。
通俗说:就是对常见数据结构和算法的封装(顺表表,链表,栈和队列,二叉树,哈希等)
STL分为以下六个组件:
详细说:
容器: 对常见数据结构的封装—>组织数据
序列式容器(线性结构):
vector:动态类型的顺序表
list:带头节点的双向链表
deque:动态的二维数组
array:静态顺序表
forward_list:带头节点的单向链表
算法:
1.与数据结构相关的:各个容器的接口
2.与数据结构无关的通用算法:sort/find
迭代器: 帮助算法遍历数据,可能先判断数据存储类型,然后按相应方法遍历
适配器/配接器: stack和queue,里面封装了链表
空间配置器: 用来进行申请和释放空间,以及对这些空间进行管理
仿函数: 可以像函数一样只用的对象