从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL(上):https://developer.aliyun.com/article/1513664
3. 类模板
C语言在讲数据结构的时候,要转化存的类型,是用 typedef 来解决的。但是要设置两个存不同类型的栈呢?CV?所以还是得用模板解决。
int main() { Stack st1; // 存int数据 Stack st2; // 存double数据 return 0; }
3.1 类模板的定义
定义:和函数模板的定义方式是一样的,template 后面跟的是尖括号 < > :
template<class T1, class T2, ..., class Tn> class 类模板名 { // 类内成员定义 };
类内定义类模板和函数模板没什么不一样,看看类外定义类模板参数:
template<class T> class Stack { public: Stack(T capacity = 4) : _top(0) , _capacity(capacity) { _arr = new T[capacity]; } ~Stack();// 让析构函数放在类外定义 private: T* _arr; int _top; int _capacity; }; // 类模板中函数放在类外进行定义时,需要加模板参数列表 template <class T> Stack<T>::~Stack() { delete[] _arr; _arr = nullptr; _capacity = _top = 0; }
3.2 类模板实例化
我们试试用C++写一部分数据结构的栈:
#include <iostream> using namespace std; template<class T> class Stack { public: Stack(T capacity = 4) : _top(0) , _capacity(capacity) { _arr = new T[capacity]; } ~Stack() { delete[] _arr; _arr = nullptr; _capacity = _top = 0; } private: T* _arr; int _top; int _capacity; }; int main() { Stack<int> st1; // 存储int Stack<double> st2; // 存储double return 0; }
函数模板之所以能推,是因为有实参传形参这么一个 "契机" ,让编译器能帮你推。你定义一个类,编译器能推吗?
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟 <> , 然后将实例化的类型放在 <> 中即可,如果用缺省值可以不放类型,但一般要放。
注意事项:
① Stack 不是具体的类,是编译器根据被实例化的类型生成具体类的模具。
template<class T> class Stack {...};
② Stack 是类名,Stack<int> 才是类型:
1. Stack<int> s1; 2. Stack<double> s2;
4. 模板初阶笔试选择题
4.1 下面有关C++中为什么用模板类的原因,描述错误的是? ( )
A.可用来创建动态增长和减小的数据结构
B.它是类型无关的,因此具有很高的可复用性
C.它运行时检查数据类型,保证了类型安全
D.它是平台无关的,可移植性
4.2 在下列对fun的调用中,错误的是( )
template <class T> T fun(T x,T y) { return x*x+y*y; }
A.fun(1, 2)
B.fun(1.0, 2)
C.fun(2.0, 1.0)
D.fun<float>(1, 2.0)
4.3 下列关于模板的说法正确的是( )
A.模板的实参在任何时候都可以省略
B.类模板与模板类所指的是同一概念
C.类模板的参数必须是虚拟类型的
D.类模板中的成员函数全是模板函数
4.4 下列的模板声明中,其中几个是正确的( )
1)template
2)template<T1,T2>
3)template<class T1,T2>
4)template<class T1,class T2>
5)template<typename T1,T2>
6)template<typename T1,typename T2>
7)template<class T1,typename T2>
8)<typename T1,class T2>
A.2
B.3
C.4
D.5
4.5 下列描述错误的是( )
A.编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础
B.函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具
C.模板分为函数模板和类模板
D. 模板类跟普通类以一样的,编译器对它的处理时一样的
答案及解析
j4.1 C
A.模板可以具有非类型参数,用于指定大小,可以根据指定的大小创建动态结构
B.模板最重要的一点就是类型无关,提高了代码复用性
C.模板运行时不检查数据类型,也不保证类型安全,相当于类型的宏替换,故错误
D.只要支持模板语法,模板的代码就是可移植的
4.2 B
A.通过参数推导,T为int,不存在二义性,调用正确
B.由于参数类型不一样,模板不支持类型转换,推导参数会产生二义性,编译错误
C.通过参数推导,T为float,不存在二义性,调用正确
D.通过类型实例化函数,调用正确
4.3 D
A.不一定,参数类型不同时有时需要显示指定类型参数
B.类模板是一个类家族,模板类是通过类模板实例化的具体类
C.C++中类模板的声明格式为template<模板形参表声明><类声明>,
并且类模板的成员函数都是模板函数
D.正确,定义时都必须通过完整的模板语法进行定义
4.4 B
A.1.模板语法错误,2.没有关键字class或typename指定类型,3.T2缺少class或typename
B.正确, 4,6,7为正确声明
C.5.T2缺少class或typename
D.8.缺少template
4.5 D
A.模板是代码复用的重要手段
B.函数模板不是一个具体函数,而是一个函数家族
C.目前涉及到的模板就两类,函数模板与类模板
D.模板类是一个家族,编译器的处理会分别进行两次编译,其处理过程跟普通类不一样
5. STL简介
5.1 什么是STL
STL —— Standard Template Libary——标准模板库,是 C++ 标准库的重要组成部分,
它不仅是一个可重复的组件库,还是个包罗数据结构与算法的软件框架。
百度百科:
标准模板库(Standard Template Library,STL)是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。虽说它主要表出现到C++中,但在被引入C++之前该技术就已经存在了很长时间。STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。
标准模板库是一个C++软件库,大量影响了C++标准程序库但并非是其的一部分。其中包含4个组件,分别为算法、容器、函数、迭代器。
模板是C++程序设计语言中的一个重要特征,而标准模板库正是基于此特征。标准模板库使得C++编程语言在有了同Java一样强大的类库的同时,保有了更大的可扩展性。
在C++标准中,STL被组织为下面的13个头文件:<algorithm>、<deque>、<functional>、<iterator>、<vector>、<list>、<memory>、<numeric>、<stack>、<queue>、<set>、<map>和<utility>。
5.2 STL的版本
原始版本(HP 版本)
Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原始版本一样做开源使用。 HP 版本--所有STL实现版本的始祖。
P. J. 版本
由P. J. Plauger开发,继承自HP版本,被Windows Visual C++采用,不能公开或修改,
缺陷:可读性比较低,符号命名比较怪异。
RW版本
由Rouge Wage公司开发,继承自HP版本,被C++ Builder 采用,不能公开或修改,可读性一般。
SGI版本
由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版本。被GCC(Linux)采用,可移植性好, 可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高。
本博客专栏后面学习STL要阅读部分源代码,主要参考的就是这个版本。
5.3 STL的六大组件
STL提供六大组件,它们之间可以相互组合使用。
以下文字看一眼就行,后面还会详细讲解。
① 容器(containers)
容器用来存放数据,包括各种数据结构,如vector,list,deque,set,map等。从实现的角度来看,STL容器是一种class template。
② 算法(algorithms)
算法包括各种常用的sort,search,copy,erase, find等等。从实现的角度来看,STL算法是一种function template。
③ 迭代器(iterators)
迭代器作为“泛型指针”,扮演容器和算法之间的粘合剂,用来连接容器和算法。从实现角度来看,迭代器是一种将operator*,operator->,operator++,operator--等指针相关操作进行重载的class template。
所有的STL容器都带有自己专属的迭代器。原生指针也是一种迭代器。所谓的原生指针就是我们定义的最普通的指针,形如 类型名 *指针名,类型名可以是基础类型int,double等,也可以是一个类。当一个类将*和->操作符进行重载时,
虽然也可进行类似指针的操作,但是它已不是原生指针。
④ 仿函数(functors)
仿函数是让一个类看起来像一个函数。其实就是一种重载了operator()的class或者class template。
⑤ 配接器(adapters)
一种用来修饰容器,仿函数或者迭代器的接口的东西。配接器修改类的接口,使原来不相互匹配的两个类可以相互匹配,进行合作。
⑥ 配置器(allocators)
配置器主要负责空间的配置和管理。从实现角度来看,配置器是一个实现了动态空间配置、空间管理、空间释放的class template。
5.4 如何学习STL
面试和笔试都经常考到STL,网上有句话说:“ 不懂 STL ,不要说你会 C++” 。C++刷题基本都会用到STL,STL是C++中的优秀作品,有STL后,许多底层的数据结构以及算法都不需要自己重新造轮子,站在前人的肩膀上,健步如飞地快速开发。如何学习 STL?
学会查文档,我们后面的学习会跟着这个文档学:
上面这个文档比较方便,但不是官方文档,官方文档:
cppreference.com
阅读英语文档是重要技能,不会的单词查一查就好了,尽量不直接用翻译软件。
建议后期阅读:
《Effctive C++》《高质量C++》《STL源码剖析》
看看大佬出的书上是怎么说的:
本专栏后面就马上更新STL的内容了,学完消耗了应该就到第二境界了。第三境界就靠自己探索了。