提高篇1
- 1
- 1.1模板的概念
- 模板并不是万能的
- 例如数组之间不能直接赋值
- 例如传入的参数是自定义的数据类型
- 泛型编程是为了提高复用性
- 模板并不是万能的
- 1.2函数模板
- 1.2.1
- 自动类型推导
- 函数模板使用注意事项
- void swap(T &a,T &b)(预先定义好的)
- swap(a,b)
- 指定显示推导
- swap<int>(a,b)
- template<typename T>//class可用于函数模板也可用于类模板
- template声明创建模板
- typename表明其后面的符号是一种数据类型,可以用class代替
- T表示的是一种通用的数据类型,名称替换,通常是一种大写字母
- 自动类型推导
- 1.2.2
- 函数模板使用注意事项
- 自动类型推导需要一致的参数类型
- 函数模板需要确定T的数据类型才可以使用
- 函数模板使用注意事项
- 1.2.4
- 普通函数和函数模板之间的区别
- 普通函数可以发生隐式类型装换
- 用函数模板时,用自动类型推导式不会发生隐式类型转换
- 使用指定显式推导时,发生隐式类型转换
- 建议使用指定显示推导,因为可以自己知道通用类型T,而不用编译器自行推导
- 普通函数和函数模板之间的区别
- 1.2.5
- 如果函数模板和普通函数均可以实现,优先调用普通函数
- 可以通过空参列表强调调用函数模板
- myprint<>(a,b)//空模板参数列表
- 函数模板也可以发生重载
- 如果函数模板可以产生更好的效果,优先调用函数模板
- 普通函数参数类型是int型的,但是参数是char型的,那么会优先调用函数模板,因为函数模板会产生更好的效果
- 1.2.6
- 模板的局限性
- 例如数组之间不能直接赋值
- 例如传入的参数是自定义的数据类型
- c++为实现这一特定的类型提供了具体化的模板
- 使用运算符重载
- 使用具体化的自定义类型函数模板
- template<> bool mycompare(person &p1,person &p2){}
- 专门处理person的函数模板
- c++为实现这一特定的类型提供了具体化的模板
- 利用具体化的模板,可以实现自定义类型的通用化
- 学习模板不是为了写模板,而是为了在使用stl能提供系统化的模板,是为了使用函数模板
- 模板的局限性
- 1.2.1
- 1.3
- 1.3.1类模板
- template<calss typename,class typeage>
- class person{
- typename name;
- typeage age;
- };
- 1.3.2类模板和函数模板的区别
- 类模板没有自动类型推导的使用方式
- 类模板在模板参数列表中可以有默认参数
- 参数列表中可写默认参数
- 例如template<class typename,class typeage= int>//typeage默认是int型
- 参数列表中可写默认参数
- 1.3.3类模板中成员函数创建的时机
- 普通类中的成员函数一开始就可以创建了
- 类模板中的成员函数在调用时才创建
- 因为不知道对象的具体类型,所以,创建不知类型的函数,不会立即创建对应的函数,既不会报错,只有调用时才会创建具体的函数
- 1.3.4类模板对象做函数参数
- 学习目标
- 类模板实例出来的对象,向函数传参的方式
- 三种传入方式(前提有一个自定义的类型person)
- typeid(T1).name看T1类型的名称
- 指定传入的类型(最常用)
- person<string,int>p("孙悟空",100)
- 参数模板化
- template<class T1,class T2>
- void printPerson2(person<T1,T2>&p)
- {}
- 整个类模板化
- template<class T>
- personshow(T &p)
- {
- p.show//展示是p的调用
- }
- void test()
- {
- person<string,int>("唐僧",30);
- personshow(p);
- }
- 学习目标
- 1.3.5类模板与继承
- 当子类继承的父类是模板时,需指定父类的参数列表类型(子类不是模板)
- 因为子类不是模板时,编译器需要分配内存空间
- 当子类是类模板时,即可灵活指定父类模板参数列表
- 当子类继承的父类是模板时,需指定父类的参数列表类型(子类不是模板)
- 1.3.6类模板成员函数的类外实现
- 构造函数和成员函数的类外实现基本一致
- 记得写模板声明
- 记得作用域
- 记得写尖括号将参数列表写进去
- 1.3.7类模板分文件编写
- 掌握分文件编写出现的问题和解决问题的方法
- #program once
- 防止头文件名重复包含
- 出现的问题
- 无法解析的外部命令
- 头文件看见了函数的声明,但是是类模板所以不创建,到链接阶段,只有头文件的话,编译器就连接不到成员函数(类模板中的成员函数创建实时机是在调用阶段)
- 解决方案
- 1.直接包含源文件(很少做,很少直接包含源码,即看源码的源文件)
- 2.将.h文件和.cpp文件直接写在一起,并命名为.hpp文件
- 调用时直接包含.hpp文件就好了
- 解决方案
- 1.3.8类模板与有元
- 掌握类模板配合有元函数的类内和类外实现
- 类内实现无需注意什么//有写代码
- 类外实现需要主要该函数是普通函数但是是函数模板,记得写参数化列表
- 可以将函数实现提前写在程序前面,让编译器认识,不然,编译器向下执行,找不到实现函数就会报错
- 构造函数应该是公共函数,不然无法用不了构造函数初始化
- 掌握类模板配合有元函数的类内和类外实现
- 1.3.9类模板案例
- 实现一个通用的数组类//有写代码
- 当创建的数据中有堆区的数据要考虑一下防止浅拷贝的问题
- 有拷贝函数和运算符重载
- 自己创建的对象无法通过下标方式访问数中的元素
- 自己重载一下[]运算符
- 1.3.1类模板
- 1.1模板的概念
- 2初识stl
- 2.1stl的诞生
- 为提高代码的复用性,为建立数据结构和算法的一套统一标准,建立了stl库(standard template library)(标准模板库)
- 2.2stl的基本概念
- stl从广义上划分为:容器(container)算法(algorithm)迭代器(iterator)
- 容器和算法通过迭代器进行衔接
- (技术采用)几乎所有的代码都采用模板类或者·模板函数
- 2.3stl六大组件
- 细分为
- 容器,算法,迭代器,仿函数,适配器(配接器),空间配置器
- 容器
- 各种数据结构。如vector,list,deque,set,map等,用来存放数据
- 算法
- 各种常用的算法,如sort,find,copy,for_each等
- 迭代器
- 扮演算法和容器之间的胶合剂
- 仿函数(重载时的小括号,协助算法完成策略变化)
- 行为类似函数,可以作为算法的某种策略
- 适配器
- 一种修饰容器或者仿函数或迭代器接口的东西
- 空间适配器()
- 负责空间的配置和管理
- 容器
- 容器,算法,迭代器,仿函数,适配器(配接器),空间配置器
- 细分为
- 2.4stl中的容器,算法,迭代器
- 容器
- 将最广泛的数据结构实现出来
- 最常用的数据结构:数组,链表,树,栈,队列,集合,映射表等
- 容器分为关联式容器和序列式容器两种
- 关联式容器
- 强调值的排序,序列式容器中每个元素均在固定的位置
- 序列式容器
- 二叉树结构,各个元素没有严格的物理上的顺序关系
- 关联式容器
- 算法
- 有限的步骤,解决数学或者逻辑上的问题,这一门学科我们叫做算法
- 算法分为质变算法非质变算法
- 质变算法
- 运算过程中会更改区间内元素的内容。例如拷贝,替换,删除
- 非质变算法
- 运算过程中不会改变区内的元素内容,例如查找,计数,遍历,寻找极值
- 质变算法
- 迭代器
- 提供一种方法,使之能够依序访问容器中的各个元素而不需暴露容器的内部结构
- 每个容器都有自己的一个专属的迭代器
- 迭代器2.5的作用类于指针,初学阶段我们可以先理解迭代器为指针
- 迭代器种类
- 容器
- 2.1stl的诞生
-
- 2.5容器算法迭代器初识
- 2.5.1vector存放内置数据类型
- 容器 vector
- 算法 for_each
- 迭代器 vector<int>::iterator
- 尾插法push_back向尾部插入数据
- begin()指向首端,end()指向尾端
- 2.5.2vector存放自定义数据类型
- 可把iterator类型的变量当成指针,*变量是拿到容器中的数据,类型是<>里面的数据类型
- 2.5.3vector容器中嵌套容器
- vector中嵌套vector
- 2.5.1vector存放内置数据类型
- 2.5容器算法迭代器初识
- 3stl常用容器
- 3.1string容器
- 3.1.1string基本概念
- string是c++风格的字符串,string本质上是一个类
- string和char*的区别
- char*是一个指针
- string是一个类,类内部封装了char*,管理这个字符串,是一个char*的容器
- 特点
- string中封装了很多成员方法
- 例如:查找find,拷贝copy,删除delete,替换replace,插入insert
- string管理char*所分配的内存,不用担心赋值越界和取值越界等等,由类内部负责
- 3.1.2string构造函数
- 构造函数原型
- string();//创建一个空的字符串,例如string str;
- string(const char* s)//使用字符串s初始化
- string(const string &str)//使用一个string对象初始化另一个string对象
- string(int n,char c)//使用n个字符c初始化
- 构造函数原型
- 3.1.3string的赋值操作
- 功能描述
- 给string字符串赋值
- 赋值的函数原型
- 功能描述
- 3.1.1string基本概念
- 3.1string容器
-
-
-
-
- 赋值方式很多一般用=
-
- 3.1.4string字符串拼接
-
-
-
-
-
- 记住几种即可
- 3.1.5string的替换和查找
-
-
-
-
-
- 查找:查找指定字符串是否存在
- 替换:在指定位置替换字符串
- rfind从右往左查找
- find是从左往右查找
- 3.1.6string字符串比较
- 字符串比较
- 按照字符的ASCII码比较
- =返回0
- <返回-1
- >返回1
- 函数原型
- string s1="hello"; string s2="world"
- s1.compare(s2);
- string s1="hello"; string s2="world"
- 主要适用于判断两个字符串是否相等
- 字符串比较
- 3.1.7string字符存取
- string里面有个函数size(),可以知道size的长度
- 通过[]访问单个字符(也可用于修改)
- string st1=“llll”; cout<<stl[1];
- 通过at访问单个字符
- cout<<str.at(i);
- 3.1.8string 的插入和删除
- 功能描述
- 对string字符进行插入和删除
- 对string字符进行插入和删除
- 功能描述
-
-
-
-
-
- 插入删除起始下标均从0号位置开始
- 3.1.9string子串
- 功能描述
- 从字符串中截取想要的子串
- 截取邮件前面的用户名
- str.substr(int pos,int s)//pos位置截取s个子串
- 功能描述
-
- 3.2vector容器
- 3.2.1vector容器基本概念
- 功能
- vector数据结构和数组非常相似,也称为单端数组
- vector与普通数组的区别
- 不同之处在于数组是静态空间,vector可以动态扩展
- 动态扩展
- 并不是在原空间后面接新空间,而是找更大的空间,然后将原数据拷贝到新空间释放原空间
- vector容器的迭代器是支持随机访问的迭代器
- 功能
- 3.2.2vector构造函数
- 功能描述
- 创建vector容器
- 创建vector容器
- 功能描述
- 3.2.1vector容器基本概念
-
-
-
-
-
- 代码示例
- 代码示例
-
-
-
-
-
- 3.2.3vector容器的赋值方式
- 功能描述
- 给vector容器赋值
- 给vector容器赋值
- 功能描述
- 3.2.3vector容器的赋值方式
-
-
-
-
- 示例
- 示例
-
-
-
-
- 3.2.4vector容量和大小
- 功能描述
- 对vector容器的容量和大小进行操作
- 函数原型
- 功能描述
- 3.2.4vector容量和大小
-
-
-
- 3.2.5vector容器的插入和删除
- 功能描述
- 对vector容器的插入和删除
- 3.2.5vector容器的插入和删除
-
-
-
- 3.2.6vector数据存取
- 功能描述
- 对vector中的数据的存取操作
- 函数原型
- 功能描述
- 3.2.6vector数据存取
-
-
-
- 3.2.7vector互换容器
- 功能描述
- 实现两个容器内元素进行互换
- 函数原型
- swap(vec)//实现vec与本身元素进行互换
- 实际用途
- 巧用swap可以收缩内存空间
- vector<int>(v).swap(v)
- 分两部分看
- vector<int>(v),创建一个用v来初始化的匿名对象,用v所用的元素个数
- 匿名对象,当前行执行完,将其回收
- .swap(v)交换容器,执行完后,匿名对象x被回收
- vector<int>(v),创建一个用v来初始化的匿名对象,用v所用的元素个数
- 巧用swap可以收缩内存空间
- 功能描述
- 3.2.8vector预留空间
- 功能描述
- 减少vector容器动态扩展时的次数
- 函数原型
- reverse(int len)//容器预留len个元素长度,预留位置不可初始化,元素不可访问
- 功能描述
- 3.2.7vector互换容器
-
-
-
-
-
-
- 如果知道扩展大小,预留空间,只需动态扩展一次
-
-
-
- 3.3deque容器
- deque容器的基本概念
- 功能
- deque容器的基本概念
-
-
-
-
-
- 双端数组,可以对头端进行插入和删除操作
- deque容器和vector容器的区别
- vector容器对于头部的插入删除效率低,数据量越大,效率越低
- deque相对而言,对头部的插入删除速度比vector快
- vector访问元素时的速度比deque快,这与两者内部实现有关
- deque内部工作原理
- deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据
- 中控器维护的是每个缓冲区的地址,使得使用deque是像一片连续的内存空间
-
-
-
-
-
-
-
- deque的迭代器也支持随机访问
-
- 3.3.2deque构造函数
- 功能描述
- deque容器构造
- 函数原型
- 功能描述
-
-
-
-
-
-
-
- 前面加const时,迭代器也要是只读的
- iterator改为const_iterator
- 前面加const时,迭代器也要是只读的
- deque和vector容器构造方式基本一样,灵活使用即可
-
-
- 3.3.3deque赋值操作
- 功能描述
- 给deque容器赋值
- 功能描述
-
-
-
-
-
- deque赋值和vector相似,需熟练掌握
- 3.3.4deque大小操作
- 功能描述
- 对deque容器的大小进行操作
- 函数原型
- deque没有容量这一概念,因为其可以无限开辟空间,而只是在中控器中加了一个地址而已
- 功能描述
-
-