C++提高编程

一、模板

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容器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值