标准C++(七)

一、模板技术

是一种自动生成代码的技术,能够让程序在编写是不需要考虑数据类型(让代码脱离数据类型),所以这种技术也叫做泛型编程技术。

HP公司使用这种技术封装了一套数据结构和算法叫STL,现已开源,被默认包含在C++标准库中。

二、为什么使用模板

1、C/C++是一种静态编程语言(预处理->汇编->编译->链接)
静态编程语言的优点是运行速度快,而缺点是实现通用的代码比较麻烦,
例如:实现一个通用的快速排序算法。
动态编程语言:html、shell、python

2、借助回调函数实现通用代码,实现的难度高,使用麻烦。

3、借助宏函数实现通用代码,实现简单,但类型检查不严格、没有返回值、容易出错。

4、借助函数重载机制实现通用代码,缺点是代码段会大量增加,但不能解决未知的类型。

5、综合以上原因,C++之父在C++中实现了模板技术,从而让C++彻底脱离数据类型。

注意:typename和class可以通过。

三、函数模板

1、函数模板的定义
template <typename T1,typename T2,...>
函数名(T1 arg1,T2 arg2)
{
    T3 ret = arg1 + arg2;
    return ret;
}

可能使用任何名字作为类型名,但使用“T”俗称约定他表示该函数指定的是任意类型。

2、函数模板的原理

模板函数会经历两次比编译:
1、检查模板的语法是否正确,但此时并不会生成二进制的指令。
2、根据调用者提供的参数类型再次检查模板代码,如果没有错误再生成二进制指令(函数代码)。

3、函数模板的调用

C++编译器并不会把模板函数当做一个函数实体,而是能够生成函数实体的工具,它能够根据调用者提供的数据类型生成出不同的函数实体。
根据调用者提供的数据类型生成函数实体的过程叫实例化。
实例化的方式:
自动实例化:根据实参的数据类型,自动实例化。
显示实例化:函数名<类型参数>(实参),当前函数的参数与模板类型没有关系时只能显式。

4、默认形参
template <typename T1,typename T2=int>
 11 T3 函数名(T1 arg1,T2 arg2)
 12 {
 13     T3 ret = arg1 + arg2;
 14     return ret;
 15 }

可以像参数的默认形参一样,给模板设置默认的类型。

5、模板的特化

模板虽好但并不能解决所有问题,有些特殊类型与普通的运算规则不同,需要给它实现一个特殊的版本,如:char*类型。
当模板函数与普通函数重名时不会冲突,会优先调用普通函数。

四、类模板的定义

template <typename T,typename M,typename R>
class Test
{
    M m_num;
public:
    Test(T t)
    {
        m_num = t;
    }
    R func(void)
    {
        R ret;
        return ret;
    }
}
2、类模板的使用

类模板也需要先实例化再使用,与函数模板不同的是它支持自动实例化,必须显式的指定类型参数实例化。

类名<类型,...> 对象;

类模板的实例化过程:
编译期:编译器将类模板实例化为类,并生成创建类对象的指令。
运行期:处理器执行创建类对象的指令,将实例化完成的类创建为对象。
注意:类模板是一种编译时的多态。(虚函数运行时多态)

3、类模板的静态成员

​ 类的静态成员在类中声明,在类外定义,在类模板中也一样,但与普通类的静态成员不同,他需要模板声明。

template <typename T,typename M,typename R>
class Test
{
    static int num;
    M m_num;
public:
    Test(T t)
    {
        m_num = t;
    }
    R func(void)
    {
        R ret;
        return ret;
    }
}
template < > 类型 类名<类型参数>::成员名;
4、递归实例化

类模板的参数可以是任何类型,只要该类型提供了模板所需要的功能。
实例化后的类模板已经是一个有效的类型了,所以它也可以当做类模板的参数来实例化类模板,我们把这种实例化叫递归实例化。

Test<Test<int>> t;
vector<vector<int>> arr;
5、类的局部特化

当某个成员函数不能做到通用,需要实现一个特殊的版本,这情况叫类的局部特化,这种局部特化函数需要在类外实现。

template<> 返回值类型 类名<类型>::函数名(参数列表)
{
	函数体;
}
6、全类特化

当需要针对某种特殊类型实现一个特殊版本的类,这怀情况叫类的全特化。

template<> 类名<类型>
{

};
7、类模板的默认参数

类模板与函数模板一样也可以设置类型的默认参数。
规则与函数默认形参基本一致(设置缺省类型的靠右)。

template <typename T1,typename T2=int>
class 类名
{

}
template <typename T1,typename T2=T1>
class 类名
{

}

缺省值可以使用前面的类型。

五、STL模板库

STL是Standard Template Library的缩写,中文名称标准模板库,由惠普实验室提供,共有三类内容:
容器:也就是以类模板形式实现的数据结构。
算法:也就是以函数模板形式实现的一些算法,如:max、min、find、sort、swap。
迭代器:容器的成员,用于帮助访问容器中的数据,使用方法类似于指针。

向量容量:vector

​ 头文件:vector
​ 采用顺序的内存存储数据,可以通过下标随机访问,也叫数组容器。
​ 优点:会随着元素的增加而自动扩展内存(在原有的基础上扩展一倍),所以也叫智能数组。
​ 支持的运算符:==、!=、<=、>=、<、>、[]
​ 常用的成员函数:
​ at() 功能相当于[]运算符,但比[]更安全,使用at越界访问时会产生异常,而[]越界访问结果是未知的。
​ back() 返回末尾的最后一个元素
​ begin() 返回一个正向迭代器,指向第一个元素。
​ end() 返回一个正向迭代器,指向最后一个元素的下一个位置。
​ capacity() 返回在不重新分配内存前容器的容量。
​ erase() 删除元素,参数必须是自己的迭代器。
​ insert() 指定的位置插入元素,该容器的插入操作效率比较低,不建议使用。
​ pop_back() 删除最后一个元素
​ push_back() 在末尾添加一个元素
​ rbegin() 返回一个逆向迭代器,指向最后一个元素。
​ rend() 返回一个逆向迭代器,指向第一个元素的上一个位置。
​ size() 返回元素的数量
​ max_size() 能容纳元素的最大值

链表容器:list

​ 头文件:list
​ 是一个功能齐全的链表容器,是最常用的容器之一。
​ 它有排序的成员函数,所有元素要它存储的元素必须支持<运算符。
​ 成员函数:
​ merge() 合并两个链接。
​ remove() 按值删除元素。

栈容器:stack

​ 头文件:stack
​ 实现了栈结构的基本功能,采用链式存储,没有迭代器,是一种FILO(先进后出)结构。
​ 支持的运算符:==、<=、>=、<、>、!=

队列容器:queue

​ 头文件:queue
​ 实现了队列结构的基本功能,采用链式存储,没有迭代器,是一种FIFO(先进先出)结构。

优先队列容器:priority_queue

​ 头文件:queue
​ 在队列的基础上,对入队的元素进行排序,然后按照排序后的结果进行出队(权重大的优先),底层采用链式存储结构,要求它存储的元素必须支持<运算符,不支持迭代器。

双向队列容器:deque

​ 头文件:queue
​ 使用方法与向量类似,它允许在头和尾快速添加、删除元素。
​ 支持的运算符:[ ]

集合容器:set

​ 头文件:set
​ 特点是元素不能重复,且会自动排序,要求它存储的元素必须支持<运算符,并且只能使用迭代器遍历。
​ 成员函数:
​ count() 获取某个元素的数量,结果只能是0或1。
​ earse() 删除元素,即可以按值删除,也可以使用迭代器删除。
​ find() 查找元素,如果找到返回指向该元素的迭代器,找不到返回end()。
​ lower_bound() 返回大于等于key值的第一个元素迭代器。
​ upper_bound() 返回大于key值的所有元素的迭代器。

多元集合容器:multiset

​ 头文件:set
​ 元素可以重复,会自动进行排序,要求它存储的元素必须支持<运算符。
​ 成员函数:
​ equal_range() 返回与给定值相等元素迭代器范围。
​ remove_if() 按条件删除,所谓的条件就一种判断函数

bool 函数(元素类型)
{
	if(条件)
		return true;
	else 
		return false;
}

​ splice() 把链表连接到指定的位置。
​ unique() 删除链表中的重复元素。

​ splice() 把链表连接到指定的位置。
​ unique() 删除链表中的重复元素。

映射容器:map

头文件:map
是一种由key/value组成的元素(字典),要求是key不能重复,会根据key自动进行排序。
key就相当于下标,可以当做访问value的凭证,它的底层采用红黑树存储,因此它的查找效率极高。支持的运算符[ ],之所以支持是因为key不能重复。
二分查找:有序
有序二叉树(不均匀)->平衡->构建速度慢
红黑树:相对平衡的二叉树,构建速度快
成员函数:
erase() 可以使用key或迭代器删除。
insert() 插入元素,可以按位置插入,也把一个迭代器的范围插入进去,注意:元素是以pair形式插入的。

pair<key_type,value_type> p(key,value);            

​ lower_bound() 返回和第一个大于等于key的元素的迭代器。
​ 返回的迭代器是指向 pair类的元素,因此使用first,second来访问。
​ upper_bound() 返回和第一个大于等于key的元素的迭代器。

多重映射容器:multimap

​ 头文件:map
​ 也是一种由 key/value 组成元素(字典)的容器,也会根据key自动进行排序,与map不同的是它的key可以重复。
​ 成员函数:
​ count() 返回键值等于key的元素个数。
​ equal_range() 返回键值为key所有元素。
​ erase() 可以使用key或迭代器删除。

STL中的容器map底层为什么使用红黑树存储?

1、有序二叉树具有极高的查找效率,但有可能不均匀导致二叉树接近链表,查询速度会大大降低。
2、为了最大限度发挥树的查找效率,要让树无线接近平衡二叉树。
3、为了形成平衡二叉树,二叉树在插入、删除时需要大量的左移、右移。
4、红黑树近似于平衡二叉树,相对平衡;但插入删除时,只需要少量的左移右移,构建速度比平衡二叉树要快的多。
5、所以使用红黑树能让有序二叉树均匀,同时又兼顾构建速度,因此map使用红黑树作为底层的存储结构。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值