C++ string 全面指南
一、模板
1. 函数模板
什么是模板呢?模板就是一个模具,只需要往这个模具里倒入不同的材料,就可以获得不同材料的铸件。
如果我们要实现一个交换函数呢?这是很容易的事情。

但是这种交换函数只能实现整型之间的交换,如果我想进行浮点数交换呢,字符型交换呢?是不是就不可以了。
虽然我们可以通过函数重载实现不同的交换函数,但是这样做太浪费时间了,没有意义。毕竟只是改变了交换函数参数的类型,代码不需要变化。所以,这种方法是有缺陷的。
1.代码复用率低。
2.可维护性差。
所以,有了函数模板,这是实现泛型编程的基础。
所谓泛型编程就是编写与类型无关的通用代码,是代码复用的一种手段。

template<typename T>就是定义了一个模板,通过一份代码就可以实现多个要求。
这里的typename也可以换成class,这两个的区别会在后面讲解。
这个就叫做函数模板,函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
函数模板的格式:template<typename T1, typename T2, ..., typename Tn>。
2. 函数模板的原理
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以,其实模板就是将本来应该我们重复性做的工作交给了编译器。

在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。
3. 函数模板的实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化。
模板参数实例化分为:隐式实例化和显示实例化。
.隐式实例化:让编译器根据实参推演模板参数的实际类型。


.显示实例化:在函数名后的<>中指定模板参数的实际类型。

4. 模板参数的匹配原则
.一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以实例化为这个非模板函数。

.对于非模板函数和同名函数模板,如果其它条件相同,在调用时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生出一个更好匹配的函数,那么将选择模板。

.模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。
5. 类模板
.类模板的定义格式
template<classT1,classT2,...,classTn>class 类模板名 {//类内成员定义};
.类模板的实例化
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
// Stack是类名,Stack<int>才是类型 Stack<int> st1;// int Stack<double> st2;// double二、STL简介
什么是STL呢?
STL是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。
那么,我们需要学习STL的哪些部分呢?

主要学习五个部分,空间配置器直接使用即可。
三、String
学习string从两方面去学习,一个是了解string类的接口,另一个便是模拟实现string。

string是被 typedef 的,真名叫做basic_string<char>,是用来存储字符的。
1. constructor
//构造函数,最常用的几个default(1)string();//无参构造copy(2)string(const string& str);//拷贝构造 from c-string(4)string(constchar* s);//字符串构造//不太常用的//从pos位置开始,拷贝str字符串的后len个字符,如果str字符串//太短或者len为npos,那就从pos位置拷贝到str字符串末尾substring(3)string(const string& str, size_t pos, size_t len = npos);//拷贝s指向的字符数组的前n个字符 from sequence(5)string(constchar* s, size_t n);//用n个连续的字符c的拷贝填充stringfill(6)string(size_t n,char c);
//赋值string(1) string&operator=(const string& str);
2. Iterators
//如果string对象是一个const类型的,函数返回const_iterator,否则,返回iterator//普通迭代器 iterator begin();//指向字符串的开始 iterator end();//指向字符串的末尾(最后一个字符的下一个位置)//const迭代器 const_iterator begin()const; const_iterator end()const;//反向迭代器//反向迭代器指向string的反向开始位置(也就是string的末尾最后一个字符) reverse_iterator rbegin(); const_reverse_iterator rbegin()const;//指向string的末尾的反向(也就是string的第一个字符的前一个位置) reverse_iterator rend(); const_reverse_iterator rend()const;
注:迭代器可以理解成像指针一样,但是迭代器不是指针。
3. Capacity
//size和length两个函数的功能是一致的//字符串的字节数 size_t size()const; size_t length()const;//字符串的容量 size_t capacity()const;//清空字符串voidclear();//判断字符串是否为空,length为0返回true,否则,返回falseboolempty()const;//n代表新的字符串的长度,c是用来填充字符串中新的字符空间的字符//如果n小于当前字符串的长度,字符串会缩短至前n个字符,删除第//n个字符之后的所有字符//如果n大于当前字符串的长度,在字符串的末尾插入字符到n个//(c是一个具体的字符,就用c来初始化,否则就用空字符初始化)voidresize(size_t n);voidresize(size_t n,char c);//请求调整字符串的容量,适应将字符串的长度更改为最多n个字符的需求//如果n > str.capacity,容器的容量会增加到n个字符(capacity >= n)//其它情况,缩小字符串的容量是一个非强制性的请求//这个函数不会影响字符串的长度和内容,也就是说即使缩容也不会//比字符串的长度小voidreserve(size_t n =0);//减少字符串的容量去适应它的size//不影响字符串的长度和内容voidshrink_to_fit();shrink_to_fit通常是异地缩容,因为无法从内存块的中间释放一部分内存。


这是在vs上运行的结果,是没有缩容的,那么,看一下g++编译器会不会进行缩容呢?

g++下也是没有缩容的。是否缩容,取决于平台。
4. Element access
//返回在字符串中pos位置的字符的引用char&operator[](size_t pos);constchar&operator[](size_t pos)const;//与[]的功能一样,这也是为什么string被吐槽的原因,设计了太//多的函数,有些函数功能是一样的,重点掌握[]的使用char&at(size_t pos);constchar&at(size_t pos)const;//返回的是字符串中最后一个字符的引用char&back();constchar&back()const;//返回的是字符串中第一个字符的引用char&front();constchar&front()const;
5. Modifiers
//在字符串的末尾追加另一个std::string str对象string(1) string&operator+=(const string& str);//字符串的末尾追加C风格的s字符串 c-string(2) string&operator+=(constchar* s);//在字符串的末尾追加单个字符character(3) string&operator+=(char c);//追加str的拷贝string(1) string&append(const string& str);//从str的subpos位置开始,拿取sublen个字符,追加到string//的对象中,如果str太短或者sublen等于npos,那就取到str的//末尾substring(2) string&append(const string& str, size_t subpos, size_t sublen);//s指向的以空字符结尾的字符序列,追加到string对象中 c-string(3) string&append(constchar* s);//取s指向的字符数组前n个字符,追加到string对象中buffer(4) string&append(constchar* s, size_t n);//n个字符c的拷贝,追加到string对象中fill(5) string&append(size_t n,char c);//在string对象的末尾添加字符c,string对象的长度增加1voidpush_back(char c);//删除string对象的最后一个字符,string对象的长度减1voidpop_back();//在pos位置插入str的拷贝string(1) string&insert(size_t pos,const string& str);//从str中的subpos位置开始,取sublen个字符,插入到string//对象中,如果str太短或者sublen等于npos,就从subpos位置//开始一直到str字符串的末尾substring(2) string&insert(size_t pos,const string& str, size_t subpos, size_t sublen);//s指向的以空字符结尾的字符序列,插入到string对象中 c-string(3) string&insert(size_t pos,constchar* s);//s指向的字符数组的前n个字符的拷贝插入到string对象中buffer(4) string&insert(size_t pos,constchar* s, size_t n);//插入字符c的n次拷贝fill(5) string&insert(size_t pos, size_t n,char c);//从pos位置开始,删除string的len个字符,如果string太短或者len为npos,就删到string的末尾。//注意,该函数默认删除string的所有字符sequence(1) string&erase(size_t pos =0, size_t len = npos);//从string对象中的pos位置,用str字符串替换掉string对象中的len个字符 string&replace(size_t pos, size_t len,const string& str);//拷贝str字符串赋值给string对象string(1) string&assign(const string& str);
注:insert,erase,replace需慎用,因为string的底层是数组,在插入,删除,数据时,都需要移动数据,这也就意味着时间复杂度为O(N),而替换数据,如果替换的字符串和 len 是相等的,那还是很高效的,但是如果不相等,也需要移动数据,时间复杂度也为O(N)。
//得到一个C风格的字符串constchar*c_str()const;//从pos位置开始查找一个string对象string(1) size_t find(const string& str, size_t pos =0)const;//从pos位置开始查找一个字符串 c-string(2) size_t find(constchar* s, size_t pos =0)const;//从pos位置查找s指向的字符数组的前n个字符buffer(3) size_t find(constchar* s, size_t pos, size_t n)const;//从pos位置查找单个字符character(4) size_t find(char c, size_t pos =0)const;//反向查找,与find的功能是一样的,只不过一个从string的开头处查找,一个从string的末尾查找string(1) size_t rfind(const string& str, size_t pos = npos)const; c-string(2) size_t rfind(constchar* s, size_t pos = npos)const;buffer(3) size_t rfind(constchar* s, size_t pos, size_t n)const;character(4) size_t rfind(char c, size_t pos = npos)const;//在字符串中查找第一个出现在指定字符集合中的字符//成功返回第一个匹配字符的位置,失败返回nposstring(1) size_t find_first_of(const string& str, size_t pos =0)const;//从pos位置开始取len个字符组成一个子串,构造一个新的string对象并返回(或者到字符串的末尾,如果len大于从pos位置开始剩余字符的长度) string substr(size_t pos =0, size_t len = npos)const;//从pos位置开始,拷贝string对象中的len个字符,存储在s指向的字符数组里 size_t copy(char* s, size_t len, size_t pos =0)const;npos是一个 size_t 类型,值为 -1,实际值是一个无穷大的数,因为 size_t 是一个无符号整型。


6. Non-member function
//获取一行字符//is输入流对象,str存储字符的字符串对象,delim提取字符的分割符(1)istream&getline(istream& is, string& str,char delim);(2)istream&getline(istream& is, string& str);
今天的文章分享到此结束,觉得不错的小伙伴给个一键三连吧。