一、模板
1.1 模板的概念
- C++除了面向对象编程,还有泛型编程的思想,主要技术就是模板
- C++提供两类模板:函数模板和类模板
1.2 函数模板
函数模板作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型带代表
1.2.1 函数模板语法
语法:
template<typename T>
函数声明或定义
解释:
1、template – 声明创建模板
2、typename – 表示后面的值是一个数据类型,可以用class代替
3、T – 通用的数据类型
#include<iostream>
using namespace std;
//函数模板
template<typename T>
//函数定义
void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
void test01_01()
{
int a = 10;
int b = 20;
//1、方式1:自动类型推导,不显示指定类型
//mySwap(a, b);
//2、方式2:显示指定参数类型
mySwap<int>(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
int main()
{
test01_01();
system("pause");
return 0;
}
1.2.2 函数模板注意点
- 1、自动类型推导,必须推导出一致的数据类型才可以使用
- 2、函数模板必须确定T的参数类型,才可以使用。
选择排序模板实现
#include<iostream>
using namespace std;
//交换模板函数
template<typename T>
void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
//选择排序模板函数
template<typename T>
void mySort(T arr[], int len)
{
for (int i = 0; i < len - 1; i++)
{
for (int j = i + 1; j < len; j++) {
if (arr[i] > arr[j])
mySwap(arr[i], arr[j]);
}
}
}
//打印模板函数
template<typename T>
void printArr(T arr[], int len)
{
for (int i = 0; i < len; i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
void test02_01()
{
int arr[] = {2,4,1,0,5,7,6,8,3};
//double arr[] = {1.22,3.45,7.43,-1.23};
//char arr[] = "fhsbajrejksdfkas";
//计算数组的长度
int len = sizeof(arr) / sizeof(int);
//选择排序
mySort(arr, len);
printArr(arr, len);
}
int main()
{
test02_01();
system("pause");
return 0;
}
1.2.3 函数模板与普通函数的区别
函数模板与普通函数的区别如下:
-
1、普通函数调用时可以发生自动类型转换(隐式类型转换)
-
2、函数模板调用时,如果利用自动类型推导,不会发生自动类型转换
-
3、如果利用显示指定类型的方式,可以发生自动类型转换
1.2.3 函数模板与普通函数的调用规则
- 1、如果函数模板和普通函数都可以实现,优先调用普通函数
- 2、可以通过空模板参数列表来强制调用模板函数
- 3、函数模板也可以发生重载
- 4、如果函数模板可以产生更好的匹配,优先调用函数模板
1.2.4 函数模板的局限性
- 模板并不是万能的,在某些场景可能无法实现。
- 利用具体化的模板,可以解决自定义类型的通用化
- 学习模板不是为了写模板,而是为了在STL中能够运用系统提供的模板
class Person
{
public:
Person(string name, int age) {
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
//模板函数,实现比较的功能。但对于具体的自定义数据,没有定义比较方法,所以无法实现
template<typename T>
bool myCompare(T& a, T& b)
{
if (a == b)
return true;
return false;
}
//模板函数具体化,实现比较Perosn类的功能
template<> bool myCompare(Person& a, Person& b) {
if (a.m_Name == b.m_Name && a.m_Age == b.m_Age)
return true;
return false;
}
1.3 类模板
1.3.1 类模板语法
作用:建立一个通用类,类中的成员、数据类型可以不具体指定,用一个虚拟的类型来代表
语法:
template<typename T> //typename可以用class代替
类
//定义类模板
template<typename nameType,typename ageType>
class Person
{
public:
Person(nameType name, ageType age)
{
this->m_name = name;
this->m_age = age;
}
void showPerosn() {
cout << "name:" <<m_name<< endl;
cout << "age:" << m_age << endl;
}
nameType m_name;
ageType m_age;
};
void test01()
{
//利用类模板生成对象
Person<string,int> p1("张三", 18);
p1.showPerosn();
}
1.3.2 类模板与函数模板区别
主要区别有以下两点:
- 1、类模板没有自动类型推导的使用方式
- 2、类模板在模板参数列表中可以有默认值
#include<iostream>
using namespace std;
//类模板的ageType默认指定为int类型: 类模板在模板参数列表中可以有默认值
template<class nameType, class ageType = int>
class Hero
{
public:
Hero(nameType name, ageType age)
{
this->m_age = age;
this->m_name = name;
}
void showHero() {
cout << "name: " << m_name << endl;
cout << "age: " << m_age << endl;
}
nameType m_name;
ageType m_age;
};
void test02_01()
{
//这里只指定了name的类型为strig, 年龄的类型默认为int,所以可以不指定
Hero<string> h1("宋江", 25.8);
h1.showHero();
}
1.3.3 类模板中成员函数创建时机
类模板中成员函数和普通类中成员函数创建时机区别:
- 普通类中的成员函数在开始时就可以创建
- 类模板中的成员函数在调用时才创建
#include<iostream>
using namespace std;
//类模板中的成员函数在调用时才创建
class Person1
{
public:
void show1() {
cout << "Person1的show1函数" << endl;
}
};
class Person2
{
public:
void show2()
{
cout << "Person2的show2函数" << endl;
}
};
//类模板
template<class T>
class MyClass
{
public:
T obj;
//类模板的成员函数
void func1()
{
obj.show1();
}
void func2()
{
obj.show2();
}
};
void test03_01()
{
MyClass<Person1> m1;
MyClass<Person2> m2;
//调用时确定数据类型,调用对应的成员函数
m1.func1();
//m1没有func2成员函数,所以会报错
//m1.func2(); //1 > E:\A工作相关\C++相关\C++练习项目\类模板\类模板\03 - 类模板的创建时机.cpp(37, 7) : error C2039 : "show2" : 不是 "Person1" 的成员
m2.func2();
}
int main()
{
test03_01();
system("pause");
return 0;
}
1.3.4 类模板对象做函数参数
类模板实例化出的对象,向函数传参的方式:
- 1、指定传入的类型:直接显示对象的数据类型
template<class T1, class T2>
class Person4
{
public:
Person4(T1 name, T2 age) {
this->name = name;
this->age = age;
}
void show()
{
cout << "姓名:" << this->name << " 年龄:" << this->age << endl;
}
T1 name;
T2 age;
};
//1. 显示指定参数类型
void showPerson4(Person4<string, int>&p)
{
p.show();
}
void test04_01()
{
Person4<string, int> p("zhangsan", 18);
showPerson4(p);
}
- 2、参数模板化:将对象中的参数变为模板进行传递
/2. 参数模板
template<class T1, class T2>
void showPerson04_02(Person4<T1, T2> p)
{
p.show();
}
void test04_02() {
Person4<string, int> p("zhangsan", 24);
showPerson04_02(p);
}
- 3、整个类模板化:将这个对象类型 模板化进行传递
//3.类模板
template<class T>
void showPerson04_03(T p)
{
p.show();
//查看类型:typeid
//class Person4<class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char> >, int>
cout << "T的类型是:" << typeid(T).name() << endl;
}
void test04_03()
{
Person4<string, int> p("lisi", 24);
showPerson04_03(p);
}
1.3.5 类模板与继承
-
1、当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
-
2、如果不指定,则编译器无法给子类分配内存
-
3、如果想灵活指定出父类中T的类型,子类也需要变为类模板
#include<iostream>
using namespace std;
template<class T>
class Person05
{
public:
T m;
};
//如果想灵活指定出父类中T的类型,子类也需要变为类模板.其中T2对应父类的模板参数T
template<class T1, class T2>
class Son :public Person05<T2>
{
public:
T1 obj;
void show()
{
cout << "子类中的T1的类型为:" << typeid(T1).name() << endl;
cout << endl<<"父类中的T的类型为:" << typeid(T2).name() << endl;
}
};
void test05_01()
{
Son<string,char> s1; //指定子类的T1为string类型,而T2也对应着父类的T为char类型
s1.show();
}
int main()
{
test05_01();
system("pause");
return 0;
}
1.3.6 类模板成员函数类外实现
#include<iostream>
using namespace std;
template<class T1, class T2>
class Person06
{
public:
Person06(T1 name, T2 age); //函数声明
/*{
this->age = age;
this->name = name;
}*/
void showPerson06();
/*{
cout << "姓名:" << this->name << " 年龄:" << this->age << endl;
}*/
T1 name;
T2 age;
};
/*类模板成员函数的类外实现,在类内有声明-
* Person06<T1,T2>表示这是一个类模板的成员函数实现,必须写
* :: 表示作用域,是哪个类的
* template<class T1, class T2>指定T1 T2
* */
template<class T1, class T2>
Person06<T1,T2>::Person06(T1 name, T2 age)
{
this->age = age;
this->name = name;
}
/*类模板成员函数的类外实现
* Person06<T1,T2>表示这是一个类模板的成员函数实现,必须写
* :: 表示作用域,是哪个类的
* template<class T1, class T2>指定T1 T2
* */
template<class T1, class T2>
void Person06<T1,T2>::showPerson06()
{
cout << "姓名:" << this->name << " 年龄:" << this->age << endl;
}
void test06_01()
{
Person06<string, int> p("李四", 25);
p.showPerson06();
}
int main()
{
test06_01();
system("pause");
return 0;
}
1.3.7 类模板份文件编写
问题:
- 类模板中成员函数创建时机是在调用阶段,导致文件编写时连接不到
解决方法:
- 1、直接包含.cpp文件
- 2、将声明和实现写在同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制。
建议使用第二种方式:
在头文件文件夹中书写.hpp文件
#pragma once
#include<iostream>
using namespace std;
template<class T1, class T2>
class Person07
{
public:
Person07(T1 name, T2 age); //函数声明
/*{
this->age = age;
this->name = name;
}*/
void showPerson07();
/*{
cout << "姓名:" << this->name << " 年龄:" << this->age << endl;
}*/
T1 name;
T2 age;
};
template<class T1, class T2>
Person07<T1, T2>::Person07(T1 name, T2 age) {
this->age = age;
this->name = name;
}
template<class T1, class T2>
void Person07<T1, T2>::showPerson07() {
cout << "姓名:" << name << " 年龄:" << age << endl;
}
#include<iostream>
using namespace std;
//第一种解决方法:直接包含源文件
//#include"Person07.cpp"
//第二种解决方法:将Person07.h和Person07.cpp中的内容写到一起,将后缀名改为.hpp文件
#include"Person07_02.hpp"
void test07_01()
{
Person07<string, int> p1("宋江",18);
p1.showPerson07();
}
int main()
{
test07_01();
system("pause");
return 0;
}
1.3.8 类模板与友元
- 掌握类模板配合友元函数的类内和类外实现
全局函数类内实现:直接在类内声明友元即可
template<class T1, class T2>
class Person08
{
//全局函数类内实现
friend void printPerson(Person08<T1,T2> p)
{
cout << "姓名:" << p.name << " 年龄:" << p.age << endl;
}
public:
Person08(T1 name, T2 age)
{
this->name = name;
this->age = age;
}
private:
T1 name;
T2 age;
};
全局函数类外实现:需要提前让编译器知道全局函数的存在
- 1、将类外全局友元函数书写在类之前。
- 2、在类外全局友元函数书之前申明类的存在
- 3、申明时,空参数列表。friend void printPerson2**<>**(Person08<T1,T2> P); //函数声明; <>空参数列表
template<class T1, class T2>
class Person08;
//全局函数类外实现:需要将类声明在前面
template<class T1, class T2>
void printPerson2(Person08<T1, T2> p) {
cout << "类外实现全局友元函数" << endl;
cout << "姓名:" << p.name << " 年龄:" << p.age << endl;
}
template<class T1, class T2>
class Person08
{
//需要加一个空参数列表
friend void printPerson2<>(Person08<T1,T2> P); //函数声明
public:
Person08(T1 name, T2 age)
{
this->name = name;
this->age = age;
}
private:
T1 name;
T2 age;
};
1.3.9 类模板案例
案例描述:实现一个通用的数组类,要求如下:
- 可以对内置数据类型以及自定义数据类型的数据进行存储
- 将数组中的数据存储在堆区
- 构造函数中可以传入数组的容量
- 提供对应的拷贝构造函数以及operator=防止浅拷贝
- 提供尾插法和尾删法对数组中的数据进行增加和删除
- 可以通过下标的方式访问数组中的元素
- 可以获取数组中当前元素个数和数组的容量
1、MyArray.hpp文件
#pragma once
#include<iostream>
using namespace std;
template<class T>
class MyArray
{
public:
MyArray(int capacity)
{
//cout << "MyArray的有参构造函数调用" << endl;
this->m_Capacity = capacity;
this->m_Size = 0;
this->pAddress = new T[this->m_Capacity];
}
//拷贝构造函数
MyArray(const MyArray& arr) {
//cout << "MyArray拷贝构造函数调用" << endl;
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
//深拷贝
this->pAddress = new T[this->m_Capacity];
//将数据拷贝
for (int i = 0; i < this->m_Size; i++)
{
this->pAddress[i] = arr.pAddress[i];
}
}
//operator=防止浅拷贝
MyArray& operator=(const MyArray& arr)
{
//cout << "MyArray的operator=函数调用" << endl;
//先判断原来堆区是否有数据,如果有则需要先释放
if (this->pAddress != NULL) {
delete[] this->pAddress;
this->pAddress = NULL;
this->m_Size = 0;
this->m_Capacity = 0;
}
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
//深拷贝
this->pAddress = new T[this->m_Capacity];
//将数据拷贝
for (int i = 0; i < this->m_Size; i++)
{
this->pAddress[i] = arr.pAddress[i];
}
//返回
return *this;
}
//尾插法
void Push_Back(const T& val)
{
//判断容量
if (this->m_Capacity == this->m_Size)
return;
this->pAddress[this->m_Size] = val;
this->m_Size++;
}
//尾删法
void Pop_Back()
{
//让用户访问不到最后一个元素
if (this->m_Size == 0) //判断为空
return;
this->m_Size--;
}
//通过下标访问数组中的元素
//重写[]. 函数调用想作为左值,就得返回引用
T& operator[](int index)
{
return this->pAddress[index];
}
//返回数组的容量
int getCapacity()
{
return this->m_Capacity;
}
//返回数组的大小
int getSize()
{
return this->m_Size;
}
~MyArray()
{
//cout << "MyArray的析构函数调用" << endl;
if (pAddress != NULL) {
delete[] this->pAddress;
pAddress = NULL;
}
}
private:
T* pAddress; //指针指向堆区开辟的真实数组
int m_Capacity; //数组的容量
int m_Size; //数组大小
};
2、main文件中
#include<iostream>
using namespace std;
#include"MyArray.hpp"
//测试自定义类型
//template<class T1, class T2>
class Person09
{
public:
Person09()
{}; //空实现
Person09(string name, int age)
{
this->name = name;
this->age = age;
}
string name;
int age;
};
void test09_01()
{
MyArray<int> arr1(100);
for (int i = 0; i < 5; i++)
{
arr1.Push_Back(i + 1);
}
//打印
for (int i = 0; i < arr1.getSize(); i++) {
cout << arr1[i]<<" ";
}
cout << endl;
cout << "数组的容量、大小分别为:" << arr1.getCapacity() <<"; " <<arr1.getSize() << endl;
/*MyArray<int> arr2(arr1);
MyArray<int> arr3(100);
arr2 = arr3;*/
}
//测试自定义类
void test09_02()
{
Person09 p1("张三", 19);
Person09 p2("李四", 26);
Person09 p3("孙悟空", 999);
Person09 p4("猪八戒", 678);
Person09 p5("唐僧", 34);
Person09 p6("沙和尚", 567);
MyArray<Person09> pArr(5);
pArr.Push_Back(p1); //尾插法加入数据
pArr.Push_Back(p2); pArr.Push_Back(p3); pArr.Push_Back(p4); pArr.Push_Back(p5); pArr.Push_Back(p6);
//打印
for (int i = 0; i < pArr.getSize(); i++) {
cout <<"姓名:"<< pArr[i].name<<" 年龄:"<<pArr[i].age << endl;
}
}
int main()
{
//test09_01();
test09_02();
system("pause");
return 0;
}
二、初识STL
2.1、STL的诞生
- C++的面向对象和泛型编程的思想,目的就是提高代码的复用性。
- 为了建立数据结构和算法的一套标准,就产生了STL
2.2、STL的基本概念
- STL(standard Template Library)标准模板库
- STL广义上分为:容器(container)、算法(algorithm)、迭代器(iterator)
- 容器和算法之间可以通过迭代器进行无缝连接
- STL中几乎所有的代码都采用了模板或者模板函数
2.3、STL六大组件
-
STL六大组件分别时:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器
① 容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据
②算法:各种常用的算法,如sort、find、copy、for_each等
③迭代器:容器和算法之间的胶合剂
④仿函数:行为类似函数,可以作为算法的某种策略
⑤适配器:一种用来修饰容器或仿函数或迭代器接口的东西
⑥空间配置器:负责空间的配置与管理
2.4、容器、算法、迭代器
STL容器就是将运用最广泛的一些数据结构实现出来
常用的数据结构:数组、链表、树、栈、队列、集合、映射表等
序列式容器:强调值的排序,序列式容器中的每个元素都有固定的位置
关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系
算法:质变算法和非质变算法
质变算法:运算过程中会改变区间中的元素的内容,比如拷贝、替换、删除等
非质变算法:运算过程中不会改变区间中的元素的内容,如查找、计数、遍历、寻找极值等
迭代器:容器与算法之间的粘合剂
每个容器都有迭代器,类似于指针
种类 | 功能 | 支持运算 |
---|---|---|
输入迭代器 | 对数据的只读访问 | 只读,支持++、==、!= |
输出迭代器 | 对数据的只写访问 | 只写,支持++ |
前向迭代器 | 读写操作,并能向前推进迭代器 | 读写,支持++、==、!= |
双向迭代器 | 读写操作,并能向前和向后操作 | 读写,支持++、– |
随机访问迭代器 | 读写操作,可以以跳跃的方式访问任意数据,功能最强的迭代器 | 读写,支持++、–、[n]、-n、<、<=、>、>= |
常用的迭代器为双向迭代器和随机访问迭代器
2.5、容器算法迭代器初始
2.5.1 vector初识:存放内置数据类型
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
void myPrint(int val)
{
cout << val << endl;
}
void test01_01()
{
//创建vector容器,数组
vector<int> v;
for (int i = 1; i < 10; i++)
{
v.push_back(10 * i);
}
//通过迭代器访问容器中的数据
vector<int>::iterator itBegin = v.begin(); //起始迭代器 指向容器的第一个元素
vector<int>::iterator itEnd = v.end(); //结束迭代器,指向容器中的最后一个元素的下一个位置
//第一种遍历方式
/*while (itBegin != itEnd)
{
cout << *itBegin << endl;
itBegin++;
}*/
//第二种
/*for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << endl;
}*/
//第三种:STL中提供的算法,for_each遍历
for_each(v.begin(),v.end(), myPrint);
}
int main()
{
test01_01();
system("pause");
return 0;
}
2.5.2 vector存放自定义数据类型
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
class Person01
{
public:
Person01(string name, int age)
{
this->age = age;
this->name = name;
}
string name;
int age;
};
void myPrint(Person01 p)
{
cout << "姓名:" << p.name << " 年龄:" << p.age << endl;
}
void test02_01()
{
Person01 p1("德玛西亚之力",43);
Person01 p2("诺克萨斯之手", 23);
Person01 p3("德邦总管赵信", 19);
Person01 p4("恕瑞玛的皇帝", 23);
vector<Person01> vPerson;
vPerson.push_back(p1); vPerson.push_back(p2); vPerson.push_back(p3); vPerson.push_back(p4);
//第一种遍历
/*for (vector<Person01>::iterator it = vPerson.begin(); it != vPerson.end(); it++)
{
cout << "姓名:" << (*it).name << " 年龄:" << (*it).age << endl;
}*/
//第二种遍历:利用自带的算法
for_each(vPerson.begin(), vPerson.end(), myPrint);
}
2.5.3 vector嵌套容器
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
void myPrint03(int val)
{
cout << val <<" ";
}
void test03_01()
{
//相当于int类型的二维数组
vector<vector<int>> vArr;
//存放数据
for (int i = 1; i < 10; i++)
{
vector<int> v;
for (int j = 1; j < 6; j++)
{
v.push_back(i*10 + j);
}
vArr.push_back(v);
}
for (vector<vector<int>>::iterator itArr = vArr.begin(); itArr != vArr.end(); itArr++) {
vector<int> temp = *itArr;
for_each(temp.begin(),temp.end(),myPrint03);
cout << endl;
}
}
int main()
{
test03_01();
system("pause");
return 0;
}
3、STL常用容器
3.1 string容器
3.3.1 string基本概念
string本质是一个类,是C++风格的字符串
string与char*的区别:
- char* 是一个指针
- string是一个类,类内部封装了char,管理这个字符串,是一个char* 类型的容器*
特点:
- string类内部封装了很多成员方法
- 例如:查找find、copy、删除delete、插入insert
- string管理char*所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责
3.1.2 string的构造函数
构造函数原型
- string() : //创建一个空字符串
- string(const char* s); : 使用字符串s初始化
- string(const string& str); :使用一个string对象初始化另一个string对象
- string(int n, char c); : 使用n个字符c初始化
3.1.3 string赋值函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N0TBbMDu-1617755889712)(C:\Users\李柏松\AppData\Roaming\Typora\typora-user-images\image-20210219153945420.png)]
3.1.4 字符串拼接
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qjJFqy98-1617755889714)(C:\Users\李柏松\AppData\Roaming\Typora\typora-user-images\image-20210219154029034.png)]
3.1.5 string查找与替换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9JTfCNEH-1617755889715)(C:\Users\李柏松\AppData\Roaming\Typora\typora-user-images\image-20210219154106597.png)]
3.1.6 字符串比较
- str1.compare(str2);
3.1.7 字符串存取
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IZiO7cMg-1617755889717)(C:\Users\李柏松\AppData\Roaming\Typora\typora-user-images\image-20210219155907725.png)]
3.1.8 string插入和删除
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VkC0LqkS-1617755889719)(C:\Users\李柏松\AppData\Roaming\Typora\typora-user-images\image-20210219160226810.png)]
3.1.9 string获取字串
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QU5PBbj2-1617755889720)(C:\Users\李柏松\AppData\Roaming\Typora\typora-user-images\image-20210219160329737.png)]
3.2、vector容器
3.3、deque容器
3.4、stack容器
3.5、queue容器
3.6、list容器
3.7、list容器
3.8、set/multiset容器
}
### 3、STL常用容器
#### 3.1 string容器
##### 3.3.1 string基本概念
**string本质是一个类,是C++风格的字符串**
**string与char*的区别:**
- char* 是一个指针
- **string是一个类,类内部封装了char*,管理这个字符串,是一个char\* 类型的容器**
**特点:**
- string类内部封装了很多成员方法
- 例如:查找find、copy、删除delete、插入insert
- string管理char*所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责
##### 3.1.2 string的构造函数
**构造函数原型**
- string() : //创建一个空字符串
- string(const char* s); : 使用字符串s初始化
- string(const string& str); :使用一个string对象初始化另一个string对象
- string(int n, char c); : 使用n个字符c初始化
##### 3.1.3 string赋值函数
[外链图片转存中...(img-N0TBbMDu-1617755889712)]
##### 3.1.4 字符串拼接
[外链图片转存中...(img-qjJFqy98-1617755889714)]
##### 3.1.5 string查找与替换
[外链图片转存中...(img-9JTfCNEH-1617755889715)]
##### 3.1.6 字符串比较
- str1.compare(str2);
##### 3.1.7 字符串存取
[外链图片转存中...(img-IZiO7cMg-1617755889717)]
##### 3.1.8 string插入和删除
[外链图片转存中...(img-VkC0LqkS-1617755889719)]
##### 3.1.9 string获取字串
[外链图片转存中...(img-QU5PBbj2-1617755889720)]
#### 3.2、vector容器
#### 3.3、deque容器
#### 3.4、stack容器
#### 3.5、queue容器
#### 3.6、list容器
#### 3.7、list容器
#### 3.8、set/multiset容器
#### 3.9、map/mutimap容器