一往情深深几许,深山夕照深秋雨。
泛型编程:函数模板和类模板
函数模板:
template<typename T> //typename也可使用class
void func(T &a){}
两种方式使用模板:
1、自动类型推导
func(a)
2、显式指定类型
func<int>(a)
模板的目的是为了提高代码的复用性,将类型参数化
注意事项:
·自动类型推导,必须推导出一致数据类型T,才可以使用
·模板必须要确定出T的数据类型,才可以使用
普通函数和模板的区别:
自动类型推导 不会发生隐式类型转换
显式制定类型 会发生隐式类型转换
普通函数和模板函数的调用规则
·如果函数模板和普通函数都可以实现,优先调用普通函数
·可以通过空模板参数列表来强制调用函数模板
·函数模板也可以发生重载
·如果函数模板可以产生更好的匹配,优先调用函数模板
模板的局限性:
模板并不是万能的,有些特定数据类型,需要用具体化方式做特殊实现
·利用具体化的模板,可以解决自定义类型的通用化
·学习模板并不是为了写模板,而是在STL能够运用系统提供的模板
类模板:
·建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型来代表
template<typename T>
类
template<class NameType, class AgeType>
class Person
{
public:
Person(NameType name, AgeType age)
{
this -> m_Name = name;
this -> m_Age = age;
}
NameType m_Name;
AgeType m_Age;
}
void test()
{
Person<string, int>p1("suwukong", 999);
}
类模板与函数模板的区别:
·类模板没有自动推导的使用方式
·类模板在模板参数列表中可以有默认参数
类模板中成员函数的创建时机:
一开始并不创建
在调用的时候才会被创建
类模板对象做函数参数
类模板实例化出的对象,向函数传参的方式
一共有三种传入方式:
1、指定传入的类型 --直接显示对象的数据类型
2、参数模板化 --将对象的参数变为模板进行传递
3、整个类模板化 --将这个对象类型 模板化进行传递
类模板与继承:
·当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
·如果不指定,编译器无法给子类分配内存
·如果想灵活指定出父类中T的类型。子类也需要变为类模板
类模板成员函数类外实现:
类模板分文件编写:
问题:
类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
解决:
·一、直接包含.cpp 源文件
·二、将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定名称,并不是强制
***********************************************************
面向对象:封装,继承和多态
STL
·standard Template Library
·STL从广义上分为:容器(container)算法(algorithm)迭代器(iterator)
·容器和算法之间通过迭代器进行无缝连接
·STL几乎所有的代码都采用了模板类或者模板函数
STL六大组件:
容器、算法、迭代器、仿函数、适配器、空间配置器
容器:就是讲运用最广泛的一些数据结构实现出来
·序列式容器
强调值得排序,序列式容器中的每个元素均有固定的位置
·关联式容器
二叉树结构,各元素之间没有严格的物理上的顺序关系
算法:有限的步骤,解决逻辑或数学上的问题,这一门学科我们叫做算法(algorithm)
·质变算法
是指运算过程中会更改区间内元素的内容,例如拷贝、替换、删除等等
非质变算法
是指运算过程中不会更改区间内元素的内容,例如查找、计数、遍历、寻找极值等等
迭代器:提供一种方法,使之能够依序寻访某个容器所含的各个元素,二又不暴露该容器内部的表示方式
string容器
本质:
·string是C++风格的字符串,而string本质上是一个类
string和char*的区别:
·char*是一个指针
·string是一个类,类内 不封装了char*,管理这个字符串,是一个char*型的容器。
特点:
string类内部封装了很多成员方法
例如:查找find,拷贝copy,删除delete,替换replace, 插入insert
string 管理char* 所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责
构造函数:
string(); //创建一个空的字符串,例如:string str;
string(const char* s); //使用字符串初始化
string(const string& str); //使用一个string对象初始化里另一个string对象
string(int n, char c); //使用n个字符c初始化
string赋值操作:
string & operator=(const char* s); //char*类型字符串 赋值给当前的字符串
string & operator=(const string &s); //把字符串s赋值给当前的字符串
string & operator=(char c); //把字符赋值给当前的字符串
string & assign(const char* s); //把字符串s赋值给当前的字符串
string & assign(const char* s, int n); //把字符串s的前n个字符赋值给当前的字符串
string & assign(const string &s); //把字符串s赋值给当前的字符串
string & assign(int n, char c); //用n个字符c赋值给当前的字符串
string查找和替换:
int find(const string & str, int pos = 0)const; //查找str第一次出现的位置,从pos开始查找
int find(const char* s, int pos = 0)const; //查找s第一次出现的位置,从pos开始查找
int find(const char* s, int pos, int n)const; //从pos查找s的前n个字符第一次位置
int find(const char c, int pos = 0)const; //查找字符c第一次出现的位置,从pos开始查找
int rfind(const string & str, int pos = npos)const; //查找str最后一次出现的位置,从pos开始查找
int rfind(const char* s, int pos = npos)const; //查找s最后一次出现的位置,从pos开始查找
int rfind(const char* s, int pos, int n)const; //从pos查找s的前n个字符最后一次位置
int rfind(const char c, int pos = 0)const; //查找字符c最后一次出现的位置,从pos开始查找
string & replace(int pos, int n, const string & str); //替换从pos开始n个字符为字符串str
string & replace(int pos, int n, const char* s); //替换从pos开始n个字符为字符串s
string字符串比较:
int compare(const string & s) const; //与字符串s比较,相等则返回 0
int compare(const char* s) const; //与字符串s比较
string字符存取:
char & operator[](int n); //通过[]方式获取字符
char & at(int n); //通过at方式获取字符
string插入和删除:
string & insert(int pos, const char*s); //在pos处插入字符串
string & insert(int pos, const string & str); //在pos处插入字符串
string & insert(int pos, int n ,char c); //在pos处插入n个c字符
string & erase(int pos, int n = npos); //删除pos开始的n个字符
string子串:
string substr(int pos = 0; int n = npos) const; //返回有pos开始的n个字符组成的字符串
vector容器:
vector构造函数:
vector<T> v; //采用模板实现类实现,默认构造函数
vector(v.begin(), v.end()); //将v[begin(), end())区间中的元素拷贝给本身
vector(n, elem); //构造函数将n个elem拷贝给本身
vector(const vector & vec); //拷贝构造函数
vector赋值操作:
vector & operator=(const vector &vec); //重载等号操作符
assign(beg,end); //将[beg,end)区间中的数据拷贝赋值给本身
assign(n,ele); //将n个elem拷贝赋值给本身
vector容量和大小:
empty(); //判断容器是否为空;
capacity(); //容器的容量
size(); //返回容器中的个数
resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值0填充新位置
//如果容器变短,则末尾超出容器长度的元素被删除
resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置
//如果容器变短,则末尾超出容器长度的元素被删除
vector插入和删除:
push_back(ele); //尾部插入元素ele
pop_back(); //删除最后一个元素
insert(const_iterator pos, ele);//迭代器指向位置pos插入元素ele
insert(const_iterator pos, int n,ele); //迭代器指向位置pos插入n个元素ele
erase(const_iterator pos); //删除迭代器指向的元素
erase(const_iterator start, const_iterator end) //删除迭代器从start到end之间的元素
clear(); //删除容器中所有的元素
vector数据存取:
at(int idx); //返回索引idx所指的数据
operator[]; //返回索引idx所指的数据
front(); //返回容器中第一个数据
back(); //返回容器中最后一个数据元素
vector互换容器:
swap(vec); //将vec与本身的元素互换
vector<int>(vec).swap(vec) //收缩内存
vector预留空间:
reserve(int len); //容器预留len个元素长度,预留位置不初始化,元素不可访问
deque容器:
·双端队列。可以对头端和尾部进行插入删除操作
deque与vector的区别:
·vector对于头部插入删除效率低,数据量越大,效率越低
·deque相对而言,对头部的插入删除速度比vector快
·vector访问元素的速度会比deque快,这和两者的内部实现有关
deque内部工作原理:
deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据
中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间
·deque容器的迭代器也是支持随机访问的
deque构造函数:
deque<T> deqT; //采用模板实现类实现,默认构造函数
deque(deq.begin(), deq.end()); //将deq[begin(), end())区间中的元素拷贝给本身
deque(n, elem); //构造函数将n个elem拷贝给本身
deque(const deque & deq); //拷贝构造函数
vector赋值操作:
deque & operator=(const deque &deq); //重载等号操作符
assign(beg,end); //将[beg,end)区间中的数据拷贝赋值给本身
assign(n,ele); //将n个elem拷贝赋值给本身
deque和大小: //deque是没有容量(capacity)的概念的
empty(); //判断容器是否为空;
size(); //返回容器中的个数
resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值0填充新位置
//如果容器变短,则末尾超出容器长度的元素被删除
resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置
//如果容器变短,则末尾超出容器长度的元素被删除
deque插入和删除: //pos的位置是迭代器,eg: deque.begin(),deque.end()
push_back(ele); //尾部插入元素ele
push_front(ele); //头部插入元素ele
pop_back(); //删除最后一个元素
pop_front(); //删除第一个元素
insert(pos, ele); //在pos位置插入一个ele元素的拷贝,返回新数据的位置
insert(pos, n, ele); //在pos位置插入n个ele数据,无返回值
insert(pos, begin, end); //在pos位置插入[begin,end)区间的数据,无返回值
clear(); //删除容器中所有的元素
erase(begin, end) //删除[begin,end)区间的数据,返回下一个数据的位置
erase(pos); // 删除pos未知的数据,返回下一个数据的位置
deque数据存取:
at(int idx); //返回索引idx所指的数据
operator[]; //返回索引idx所指的数据
front(); //返回容器中第一个数据
back(); //返回容器中最后一个数据元素
deque排序
#include <algorithm>
sort(iterator begin, iterator end) //对begin到end区间内的元素进行排序
//对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序
stack容器:
概念:stack是一种先进后出(First in Last out, FILO)的数据结构,它只有一个出口
常用接口:
构造函数:
stack<T> stk; //stack采用模板实现,stack对象默认构造形式
stack(const stack &stk); //拷贝构造函数
赋值操作:
stack & operator=(const stack &stk); //重载=操作符
数据存取:
push(elem); //向栈顶添加元素
pop(); //从栈顶移除第一个元素
top(); //返回栈顶元素
empty(); //判断堆栈是否为空
size(); //返回栈的大小
queue容器:
概念:Queue是一种先进先出(First in First out, FIFO)的数据结构,它有连个出口
常用接口:
构造函数:
queue<T> que; //queue采用模板类实现,queue对象的默认构造形式
queue(const queue &que); //拷贝构造函数
赋值操作:
queue & operator=(const queue &que); //重载=操作符
数据存取:
push(elem); //往队尾添加元素
pop(); //从对头移除第一个元素
back(); //返回最后一个元素
front(); //返回第一个元素
empty(); //判断队列是否为空
size(); //返回队列大小
list容器:
功能:将数据进行链式存储
链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的
链表的组成:
链表是由一系列结点组成
结点组成:
一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域
STL中的链表是一个双向循环列表
优点:
采用动态分配,不会造成内存浪费和溢出
链表执行插入合入删除操作十分方便,修改指针即可,不需要移动大量元素
缺点:
链表灵活,单数空间(指针域)和时间(遍历)额外耗费较大
LIst的重要性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的。
list构造函数:
list<T> lst; //list采用模板类实现,对象的默认构造形式
list(begin, end); //构造函数将[beg, end)区间中的元素拷贝给本身。
list(const list &lst); //拷贝构造函数
list(n, elem); //构造函数将n个elem拷贝给本身
list的赋值和交换:
assign(begin, end); //将[begin, end)区间中的数据拷贝赋值给本身
assign(n, ele); //将n个elem拷贝赋值给本身
list& operator=(const list &lst); //重载等号操作符
swap(lst); //将lst与本身元素互换
list大小操作:
size(); //返回容器中元素的个数
empty(); //判断容器是否为空
resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置
//如果容器变短,则末尾长处容器长度的元素被删除
resize(num ,elem) //重新指定容器的长度为num,若容器变长,则elem填充新位置
//如果容器变短,则末尾长处容器长度的元素被删除
list插入和删除:
push_back(elem); //在容器尾部添加一个元素
pop_back(); //删除容器中最后一个元素
push_front(elem); //在容器开头插入一个元素
pop_front(); //从容器开头移除第一个元素
insert(pos, elem); //在pos位置插入elem元素的拷贝,返回新的数据位置
insert(pos, n, elem); //在pos位置插入n个elem元素的拷贝,无返回值
insert(pos, begin, end);//在pos位置插入[begin, end)区间的数据,无返回值
clear(); //移除容器中的所有数据
erase(begin, end); //删除[begin, end)区间的数据,返回下一个数据的位置
erase(pos); //删除pos位置的数据,返回下一个数据的位置
remove(elem); //删除容器中所有的与elem值匹配的元素
list数据存取,排序,反转:
front(); //返回第一个元素
back(); //返回最后一个元素
reverse(); //反转链表
sort(); //链表排序
set/multiset容器:
set基本概念:
所有元素都会在插入时自动排序
本质:
set/multiset属于关联式容器,底层结构是用二叉树实现。
set和multiset区别:
set不允许容器中有重复元素
multiset允许容器中有重复元素
set构造和赋值:
set<T> st; //默认构造函数
set(const set &st); //拷贝构造函数
set & operator=(const set &st); //重载等号操作符
size(); //返回容器中元素的数目
empty(); //判断容器是否为空
swap(st); //交换两个容器
set插入和删除:
insert(elem); //在容器中插入元素
clear(); //清除所有元素
erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(begin, end); //删除区间[begin, end)的所有元素,返回下一个元素的迭代器
erase(ele); //删除容器中值为ele的元素
set查找和统计:
find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回,set.end();
count(key); //统计key的元素个数
pair对组:
pair<type,type> p (value1, value2);
pair<type,type> p = make_pair(value1, value2);
set容器排序:
自定义的数据类型,都要指定排序规则
仿函数
map/multimap容器:
map基本概念:
map中所有元素都是pair
pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
所有元素都会根据元素的键值排序
本质:
map/multimap属于关联式容器,底层结构是二叉树实现
优点:
可以根据key快速找到value值
map和multimap的区别:
map不容许容器中有重复key值元素
multimap允许容器中有重复的key值元素
map构造函数和赋值:
//map中所有元素都是成对出现,插入数据的时候要使用对组
map<T1, T2> mp; //map默认构造函数
map(const map &mp); //拷贝构造函数
map& operator=(const map &mp); //重载等号操作符
map的大小和交换:
size(); //返回容器中元素的数目
empty(); //判断容器是否为空
swap(mp); //交换两个集合容器
map插入和删除:
insert(elem); //在容器中插入元素elem
clear(); //清除所有元素
erase(pos); //删除pos迭代器所指的元素,返回下一个元素
erase(begin,end); //删除区间[begin, end)的所有元素,返回下一个元素的迭代器
erase(key); //删除容器中值为key的元素
map查找和统计:
find(key); //查找key是否存在,若存在,则返回该键的元素的迭代器;若不存在,返回set.end()
cout(key); //统计key元素的个数
map容器排序:
map容器默认排序规则为:按照key值进行 从小到大排序
利用仿函数,改变排序规则
*黑马程序员c++课程学习笔记