1. 内存分区模型

1.1 模型

  • 运行前 - 代码区 - 只读 - 共享
    • 全局区
  • 运行后
    • 栈区
    • 堆区
      • 利用new关键字,可以将数据开辟到堆区,默认局参在栈区
      • 例:int * p = new int(10);(指针接受堆区的地址) test

1.2 new操作符

  1. new返回的是该数据类型的指针
  2. float * p = new float (2.1); int * arr = new int [10];
  3. delete p ; (释放p的内存) delete[] arr ;

2. 引用

2.1 引用的基本引用

数据类型 &别名 = 原名
  • 引用必须初始化
  • 引用后不可再次更改

2.2 引用作函数参数

void test1 (int &a , int &b){};//a,b分别为实参a,b名字相同的引用别名
void test2 (int *a , int *b){};
int main(){
    int a,b;
    test1(a,b);  //引用传递
    test2(&a,&b);//地址传递
}

2.3 引用作函数返回值

  1. 不可返回局部变量的引用
int& test01(){
    int a = 10;
    return a;
}
 
int mian(){
   int &ref = tset01();//错误
}
//操作系统只会做一次保留
  1. 函数调用可作为左值
int& test02(){
    static int a = 10;//全局变量,程序结束后才释放
    return a;
}
 
int mian(){
   int &ref = tset02();//正确
   print//10
   test02()=1000;
   print//1000
}
//操作系统只会做一次保留
  1. 引用的本质
    • 常量指针
int a = 10;
int& ref = a; //即int* const ref = &a;

2.4 常量引用

  • 防止调用的函数修改形参!
  • 通常修饰形参
int& ref = 10;//错误
const int& ref = 10;//正确,加入const后,编译器将其修改为
                    //int emp=10;const int& ref=temp;
 

3. 函数提高

3.1 函数默认参数

int func1(int a,int b =2,int c=3){}//调用func1时可不加b,c
//1,某位置已有默认参数,则这个位置后都要有默认值
 
//2,如果函数声明有默认参数,函数实现就不能有默认参数

3.2 函数占位参数

void func(int a,int){}

3.3 函数重载

  1. 同一作用域下
  2. 函数名称相同
  3. 函数参数类型不同,个数不同,顺序不同
void func(){}
void func(int a){}
  1. 注意事项(15课)
    1. 引用作为重载的条件
    2. 函数重载作为默认参数

4 .类和对象

4.1 封装

class
{
public:
//属性
//行为
private:
}
  • 类中的属性和行为一般称为成员
    • 属性又称:成员属性,成员变量
    • 行为又称:成员函数,成员方法

4.1.1 访问权限

  • 公共权限: public, 类外可访问
  • 保护权限: protected,类外不可访问 ,儿子可以访问父亲中的保护内容
  • 私有权限: private, 类外不可访问, 儿子不可以访问父亲的私有内容

4.1.2 class 与 struct 区别

4.1.3 封装实例

#include<iostream>
#include<string.h>
using namespace std;
 
class Cube
{
public:
	int get_L() {
		return m_L;
	}
	void set_L(int a) {
		m_L = a;
	}
 
	int get_W() {
		return m_W;
	}
	void set_W(int a) {
		m_W = a;
	}
 
 
	int get_H() {
		return m_H;
	}
	void set_H(int a) {
		m_H = a;
	}
 
	int calculateS() {
		return 2 * m_L + 2 * m_W + 2 * m_H;
	}
 
	int calculateV() {
		return m_H * m_L * m_W;
	}
	//利用成员函数判断是否相等
	bool isSame(Cube c1,Cube c2) {
		if (c1.m_H == c2.m_H && c1.m_L == c2.m_L && c1.m_W == c2.m_W) {
			cout << "ture" << endl;
		}
		else
			cout << "false" << endl;
		return 0;
	}
 
private:
	int m_L;
	int m_W;
	int m_H;
 
};
 
int main() {
	class Cube c1;
	c1.set_L(10);
	c1.set_W(20);
	c1.set_H(30);
 
	cout << "cube长度为" << c1.get_L() << endl;
	cout << "cube面积为" << c1.calculateS() << endl;
	cout << "cube体积为" << c1.calculateV() << endl;
 
	class Cube c2;
	c2.set_L(10);
	c2.set_W(20);
	c2.set_H(33);
 
	c1.isSame(c1, c2);
}

4.2 对象特征

4.2.1 构造函数

person()
{普通构造函数}
 
person(const person &p)
{age=p.age;}//拷贝构造函数
  1. 分类

    1. 按参数:有参构造与无参(默认)构造
    2. 按类型:普通构造与拷贝构造
  2. 调用

    1. 括号法:
      • person p1;
      • person p2(10);//有参构造函数
      • person p3(p2);//拷贝构造函数
    2. 显示法:
      • person p1;
      • person p2 = person(10);//有参构造
      • person p3 = person p2;//拷贝构造
    3. 隐式转换法:
      • person p4 = 10;//相当于person p4 = person(10);//有参构造
      • person p5 = p4;//拷贝构造

    拷贝函数构造时机

    • 使用一个已经创建的对象初始化一个新对象(省劲)
    • 值传递的方式给函数参数传值(系统也干了)
    • 值方式返回局部对象(如果调用函数返回值式p1) 深拷贝与浅拷贝
    • 深:在堆区重新申请空间,进行拷贝操作(自己定义拷贝构造new解决)
    • 浅:简单的复制拷贝操作

4.2.2 析构函数

~person()
{
//析构函数
}

4.2.3 初始化列表

...
person (int a,int b,int c):m_A,m_B,m_C
{
 
}
...
 
int main(){
person p (1,2,3);
}

4.2.4 类对象作为类成员

#include<iostream>
#include<string>
using namespace std;
 
class Phone
{
public:
	Phone(string pName) {
		m_PName = pName;
	}
	string m_PName;
 
};
 
class Person
{
public:
	string m_Name;
	Phone m_Phone;
	Person(string name, string pname) :m_Name(name),m_Phone(pname)
	{
 
	}
};
 
void test01() {
	Person p ("段鑫", "iPhone13min");
	cout << p.m_Name << "拥有" << p.m_Phone.m_PName << endl;
}
 
int main() {
	test01();
	system("pause");
}
 

4.2.5 静态成员

  • 类内声明,类外初始化
class person
{
static int m_A;
}
int person::m_A = 100;//1,用类名访问cout<<perosn::m_A<<endl;2,通过对象访问

4.2.6 静态成员函数

4.2.7 类外创建成员函数

语法: “返回类型 类名 :: 函数名(){};

GoodGay::GoodGay()//38课
{
  buding = new Building;
}
void GoodGay::visit01()//调用函数
{
...
}

4.3 对象模型和this指针

4.3.1 成员变量与成员函数分开储存

4.3.2 this 指针的使用

class person //1.区分形参与成员变量同名的情况
{
person& personAddPerson(person p)
  {
  this->age += p.age;
  return *this; //在类的非静态成员函数中返回对象本身
  }
}
 
p2.personAddPerson(p1).personAddPerson(p1);//链式编程

4.3.3 空指针访问成员函数

class person
{
  public:
    void showPerson() const 
    // const person * const this
    //在成员函数后面加const,修饰的式this指向,让其不被修改
    { 
      m_A = 100;//报错
      this->m_B = 100;
    }
 
int m_A;
mutable int m_B;//特殊变量,即使在常函数中也可修改这个值
 
}
 
void test(){
 const person p;
 p.func();//报错,常对象只能调用常函数
}

4.4 友元

4.4.1 全局函数作友元

class Building
{
  friend void goodguy(Building* b);//全局函数作友元
  friend class goodGuy;//4.4.2类作友元
  friend void GoodGay::visit();//4.4.3成员函数作友元
  
  public:
  {
  ...
  }
  private:
...
}

4.4.2 类作友元

4.3.3 成员函数作友元

4.5 运算符重载

  • 对已有的运算符重新进行定义,赋予其另一种功能,以应对不同的数据类型

5.4.1 加法运算符重载

class Person
{
public:
	/*Person operator+(Person& p)
	{
		Person temp;
		temp.m_A = this->m_A + p.m_A;
		temp.m_B = this->m_B + p.m_B;
		return temp;
	}*/
 
	int m_A;
	int m_B;
 
};
 
Person operator+(Person& p1,Person& p2)
{
	Person temp;
	temp.m_A = p2.m_A + p1.m_A;
	temp.m_B = p2.m_B + p1.m_B;
	return temp;
}
 
void test01() {
	Person p1;
	p1.m_A = 10;
	p1.m_B = 10;
	Person p2;
	p2.m_A = 10;
	p2.m_B = 10;
 
	Person p3 = p1 + p2;
 
	cout << p3.m_A << p3.m_B << endl;
}
 
 
int main() {
	test01();
	system("pause");
}

5.4.2 左移运算符重载

ostream& operator << (osteam& out,Person& p){//本质operator<<(cout,p)
  out  << p.m_A << p.m_B;
  return out;//可以使之再次使用
}

5.4.3 递增运算符重载

MyInteger& operator++()//&为保证操作数一直正确
{
  m_Num++;
  return *this;//返回自身
}
//MyIntrger为自定义整型
 
//重载后置++运算符
MyInteger operator++(int)//int代表占位参数,可用于区分前置和后置递增
{
	//先记录结果
	MyInteger temp= *this;
	//后递增
	m_Num++;
	//最后返回记录的结果
	return temp;
	
 
 

5.4.4 赋值运算符重载

...
person(int age)
{
  //将年龄数据开辟到堆区
  m_Age = new int(age);
}
 
 
person& operator=(person &p)
{
  //m_Age = p.m_Age;
  //编译器提供的式浅拷贝
  if(m_Age!=Null){
    delete m_Age;
    m_Age=null;
  }
  m_Age = new int(*p.m_Age);
  return *this;
}

5.4.5 关系运算符重载

bool operator==(person &p)
{  
  if(this->m_Age == p.m_Age && this->m_Name == p.m_Name){
    return true;
  }
  return false;
}

5.4.6 函数调用运算符重载

  • 又称仿函数

4.6 继承

  • 减少代码重复量

4.6.1 继承的基本语法

  • class A : public B;
  • A类称为子类(派生类
  • B类称为父类(基类
//公共页面
class BasePage
{
public:
	void header() {
		cout << "header" << endl;
	}
	void footer() {
		cout << "footer" << endl;
	}
	void left() {
		cout << "left" << endl;
	}
};
 
 
class Java :public BasePage
{
public:
	void content() {
		cout << "this is Java" << endl;
	}
};
 
class Python :public BasePage
{
public:
	void content() {
		cout << "this is Python" << endl;
	}
};
 
class Cpp :public BasePage
{
public:
	void content() {
		cout << "this is c++" << endl;
	}
};
 
 
 
void test01() {
	//Java
	cout << "Java如下:  " << endl;
	Java ja;
	ja.header();
	ja.footer();
	ja.left();
	ja.content();
	cout << "--------------------" << endl;
	//Python
	cout << "Python如下:  " << endl;
	Python py;
	py.header();
	py.footer();
	py.left();
	py.content();
	cout << "--------------------" << endl;
	//c++
	cout << "C++如下:  " << endl;
	Cpp c;
	c.header();
	c.footer();
	c.left();
	c.content();
	cout << "--------------------" << endl;
}
 
int main() {
	test01();
}

4.6.2 继承方式

  • 公有继承:public
  • 保护继承:protected
  • 私有继承:private

4.6.3 继承中的对象模型

  • vs开发人员命令工具

4.6.4 继承中的构造和析构顺序

  • 先构造夫类后构造子类
  • 先析构子类在析构父类

4.6.5 继承中同名成员处理

  • 优先访问子类同名成员
  • 子类对象加作用域可以访问到父类同名成员
  • 当子类和父类拥有同名的成员函数,子类会隐藏父类中的成员函数,同样需要加作用域
class Base
{
public:
 
	int m_A;
 
	Base() {
		m_A = 100;
	}
	void func() {
		cout << "base-func调用" << endl;
	}
 
	void func(int) {
		cout << "bas-func(int)调用"<<endl;
	}
 
};
 
class son : public Base {
public:
 
	int m_A;
 
	son() {
		m_A = 200;
	}
 
	void func() {
		cout << "son-func调用" << endl;
	}
 
};
 
void test01() {
	son s;
	cout << s.m_A << endl;
	cout << s.Base::m_A << endl;
 
	s.func();
	s.Base::func();
	s.Base::func(10);//加作用域
}
 
int main() {
	test01();
}

4.6.6 继承中静态同名成员处理

class Base
{
public:
 
	static int m_A;
 
	Base() {
		m_A = 100;
	}
	static void func() {
		cout << "base-func调用" << endl;
	}
 
	static void func(int) {
		cout << "bas-func(int)调用"<<endl;
	}
 
};
 
int Base::m_A = 100;
 
class Son : public Base {
public:
 
	static int m_A;
 
	Son() {
		m_A = 200;
	}
 
	static  void func() {
		cout << "son-func调用" << endl;
	}
 
};
 
int Son::m_A = 200;
 
void test01() {
	Son s;
	cout << s.m_A << endl;
	cout << s.Base::m_A << endl;
 
	//通过类名访问
	cout << Son::m_A << endl;
	cout << Son::Base::m_A << endl;//
 
	s.func();
	s.Base::func();
	s.Base::func(10);
 
	//通过 类名访问
	Son::func();
	Son::Base::func();
	Son::Base::func(10);//
 
}
 
int main() {
	test01();
}

4.6.7多继承语法

4.6.8 菱形继承

4.7 多态

4.7.1 多态的基本概念

  1. 静态多态:函数重载 和 运算符重载属于静态多态,复用函数名
  2. 动态多态:派生类和虚函数实现运行时多态
  • 区别:编译阶段确定函数地址和运行阶段确定函数地址

父类指针指向子类对象

class Animal
{
public:
	virtual void speak() {
	//virtual关键字,变为虚函数,在编译器编译的时候不能确定函数调用了
		cout << "动物在说话" << endl;
	}
};
 
class Cat :public Animal
{
public:
	void speak() {
		cout << "小猫在说话" << endl;
	}
};
 
 
void doSpeak(Animal& animal) {
	animal.speak();
}//多态满足条件:
//有继承关系,子类重写父类中的函数
//多态使用:
//父类指针或引用指向子类对象
 
void test01() {
	Cat cat;
	doSpeak(cat);
}
 
int main() {
	test01();
}
 
//重写:函数返回值 函数名 函数列表 完全一致称为重写

4.7.2 多态案例一:计算器类

 
//class Calculator
//{
//public:
//	int m_Num1;
//	int m_Num2;
//
//	int getResult(string opr) {
//		if (opr == "+") {
//			return m_Num1 + m_Num2;
//		}
//		if (opr == "-") {
//			return m_Num1 - m_Num2;
//		}
//	}
//	
//};
 
class AbstractCalculator//抽象类计算器
{
public:
	int m_Num1;
	int m_Num2;
 
	virtual int getResult() {
		return 0;
	}
};
 
class addCalculator :public AbstractCalculator//具体计算器
{
public:
	int getResult() {
		return m_Num1 + m_Num2;
	}
};
 
class subCalculator :public AbstractCalculator//具体计算器
{
public:
	int getResult() {
		return m_Num1 - m_Num2;
	}
};
 
 
//void test() {
//	Calculator c;
//	c.m_Num1 = 7;
//	c.m_Num2 = 4;
//	cout <<"+为"<< c.getResult("+") << endl;
//	cout << "-为" << c.getResult("-") << endl;
//}
 
void test01() {
	AbstractCalculator * abc = new addCalculator;
	abc->m_Num1 = 7;
	abc->m_Num2 = 4;
	cout << "+为" << abc->getResult() << endl;
	delete abc;
}
 
void test02() {
	AbstractCalculator* abc = new subCalculator;
	abc->m_Num1 = 7;
	abc->m_Num2 = 4;
	cout << "-为" << abc->getResult() << endl;
	delete abc;
}
 
int main() {
	/*test();*/
	test01();
	test02();
}

4.7.3 纯虚函数和抽象类

class Base
{
public:
	virtual void func() = 0;//纯虚函数:只要有一个,这个类称为抽象类
	//抽象类特点
	//1,无法实例化对象
	//1,抽象类的子类必须重写父类中的纯虚函数,否则也称为抽象类
};
 
class Son :public Base
{
public:
	virtual void func() {
		cout << "func调用" << endl;
	}
};
 
void test01() {
	/*Son s;*///子类必须重写父类中的纯虚函数,否则无法实例化对象
 
	Base* base = new Son;//父类指针指向子类对象
	base->func();
}
 
int main() {
	test01();
}

4.7.4 多态案例二:制作饮品

class AbstractDrinking
{
public:
	virtual void Boil() = 0;
	virtual void Brew() = 0;
	virtual void PourInCup() = 0;
	virtual void PutSomeThing() = 0;
 
	void makeDrink() {
		Boil();
		Brew();
		PourInCup();
		PutSomeThing();
	}
};
 
class Coffe :public AbstractDrinking
{
public:
	virtual void Boil() {
		cout << "农夫山泉" << endl;
 
	};
	virtual void Brew() {
		cout << "冲泡咖啡" << endl;
	};
	virtual void PourInCup() {
		cout << "倒入杯中" << endl;
	};
	virtual void PutSomeThing() {
		cout << "加入咖啡和牛奶" << endl;
	};
 
};
 
class Tea :public AbstractDrinking
{
public:
	virtual void Boil() {
		cout << "怡宝" << endl;
 
	};
	virtual void Brew() {
		cout << "冲泡茶叶" << endl;
	};
	virtual void PourInCup() {
		cout << "倒入杯中" << endl;
	};
	virtual void PutSomeThing() {
		cout << "加入柠檬和枸杞" << endl;
	};
 
};
 
void doWork(AbstractDrinking* abs)//AbstractDrinking * abs= new Coffe
{
	abs->makeDrink();
	delete abs;
}
 
void test01() {
	doWork(new Coffe);
}
 
int main() {
	test01();
}

4.7.5 虚析构和纯虚析构

  • 父类的指针在析构时候,不会调用子类的析构函数,导致子类如果又堆区属性,出现内存泄漏

  • 虚析构语法:析构函数前加virtual “virtual ~Animal(){}

  • 纯虚析构语法:析构函数前加virtual =0;后加具体代码实现 virtual ~Animal() = 0; Animal::~Animal(){}“

5. 文件操作

  • ofstream:写操作
  • ifstream:读操作
  • fstream:读写操作

5.1 文本文件

写文件

  1. 包含头文件:include< fstream >//不然会出现:无法声明不完整的对象
  2. 创建流对象:ofstream ofs;
  3. 打开文件:ofs.open(“文件路径;打开方式”);(ios::out)
  4. 写数据:ofs <<“数据”;
  5. 关闭文件:ofs.close();
  • 打开方式:。。。

读文件

  1. 包含头文件
  2. 创建流对象:ifstream ifs;
  3. 打开文件,并判断是否打开成功:ifs.open(“test.txt”,ios::in);
  • if(!ifs.is_open()){};
  1. 读数据
char buf[1024]={0};
while (ifs>>buf)
{
  cout<<buf<<endl;
}
char buf[1024]={0};
while (ifs.getline(buf,sizeof(buf)))
{
  cout<<buf<<endl;
}
string buf;
while (getline(ifs,buf))
{
  cout<<buf<<endl;
}

5.1.1 删除文件

ofstream ofs("文件名",ios::trunc);

5.2 二进制文件

打开方式:ios::binary

5.2.1 写文件

``ostream& write(const char*) buffer,int len);``

5.2.2 读文件

``istream& read(char *buffer,int len);``

6. 模板

6.1 基本概念

  • c++的另一种编程思想称为泛型编程,主要利用的技术为模板
  • c++提供两种模板机制:函数模板和类模板;

6.2 函数模板

6.2.1 函数模板的语法

template<typename T>//typename=class
函数声明或定义
template<typename T>
void mySwap(T& a, T& b) {//(模板必须确定出T的数据类型才可使用)
	T temp = a;
	a = b;
	b = temp;
}
 
int main() {
	int a = 2;
	int b = 7;
	
	//1,自动类型推导(必须推导出一致的数据类型T才可使用)
	mySwap(a, b);
 
    //2,显示指定类型
	mySwap<int>(a, b);
	
	cout << a << b << endl;
}

6.2.2 普通函数和函数模板的区别

  • 普通函数调用时可以发送自动类型转换(隐式类型转换)
  • 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
  • 如果利用显示指定类型的方式,也可以发生隐式类型转换

6.2.3 普通函数和函数模板的调用规则

  1. 如果函数模板和普通函数都可以实现,优先调用普通函数
  2. 如果函数模板可以产生更好的匹配优先调用函数模板
  3. 函数模板也可以发生重载
  4. 可以通过空模板参数列表来调用函数模板//myPrint<>(a,b);

6.3 类模板

6.3.1 模板的局限性

6.3.2 类模板与函数模板区别

  1. 类模板没有字段类型推导的使用方法
  2. 类模板在模板参数列表中可以用有默认参数
template<class NameType,class AgeType> 
//template<class NameType,class AgeType=int> 
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 p("宋上",12);1,错误,无法用自动类型推导
  Person<string,int>p("宋上"12);
  //Person<string>p("宋上",12);
    //2,类模板在模板参数列表中可以用有默认参数
}

6.3.3 类模板中成员函数创建时机

  • 普通类中的成员函数一开始就可以创建
  • 类模板中的成员函数在调用时才创建

6.3.4 类模板对象作函数参数

template<class T1,class T2> 
class Person
{
public:
  Person(T1 name,T2 age)
  {
    this->m_Name=name;
    this->m_Age=age;
  }
 
  void showPerson(){
   cout<< <<endl;
  }
  NameType m_Name;
  AgeType m_Age;
}
 
//1,指定传入类型
void printPerson1(Person<string,int>&p){
  p.showPerson();
}
 
void west01(){
  Person<string,int>p("孙武看",200);
  ptintPerson1(p);
}
 
//2.参数模板化
template<class T1,class T2>
void printPerson2(Person<T1,T2>&p){
  p.showPerson();
}
 
void west02(){
  Person<string,int>p("孙武看",200);
  ptintPerson2(p);
 
 
//3.整个类模板化
template<class T>
void printPerson3(T &p){
  p.showPerson();
}
 
void test03(){
  Person<string,int>p("唐僧",40);
}
 

6.3.5 类模板与继承

template<class T>
class Base
{
  T m;
}
class Son:public Base<int>//必须要知道父类中的T类型才能继承
{
 
}
 
template<class T1,class T2>
class Son2:public Base<T2>
//如果想灵活指定父类中T的类型,子类也需要变类模板
{
  T1 obj;
}
void test02(){
  Son2<int,char>S2;
}

6.3.4 类模板成员函数类外实现

template<class T1,class T2>
void Person<T1,T2>::showPerson()
{
}

6.3.5 类模板分文件编写

6.3.6 类模板与友元

  • 全局函数类内实现-直接在类内声明友元即可
  • 全局函数类外实现-需要提前让编译器知道全局函数的存在

6.3.7 类模板案例

7. STL - 常见容器

  • Standard Template Library,标准模板库
  • 广义为:容器(container)算法(algorithm)迭代器(iterator)

7.1 STL初识

  1. 容 器:各种数据结构,如vector,list,deque,set,map等,用来存放数据
  2. 算 法:各种常用的算法:如sort,find,copy,for_each等
  3. 迭代器:扮演容器与算法之间的胶合剂
  4. 仿函数:行为类似函数,可作为算法的某种策略
  5. 适配器:用来修饰容器或者仿函数或迭代器接口的东西
  6. 空间配置器:负责空间的配置与管理

7.1.1 容器,算法,迭代器

容器

  • 序列式容器
  • 关联式容器 算法
  • 质变算法
  • 非质变算法 迭代器
  • 类似指针

7.1.2 vectorc存放自定义数据类型(遍历容器)

class Person
{
public:
	Person(string name, int age) {
		mName = name;
		mAge = age;
	}
	string mName;
	int mAge;
};
 
void test01() {
 
	vector<Person>v;
	
	Person p1("aaa", 10);
	Person p2("bbb", 20);
	Person p3("ccc", 30);
	Person p4("ddd", 40);
	Person p5("eee", 50);
	Person p6("fff", 60);
 
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	v.push_back(p5);
	v.push_back(p6);
 
	for (vector <Person>::iterator it = v.begin(); it != v.end(); it++) {
		cout << "Name= " << (*it).mName << "Age= " << (*it).mAge << endl;//it为指针(迭代器)
	}
}
void test02() {
 
	vector<Person*>v;
 
	Person p1("aaa", 10);
	Person p2("bbb", 20);
	Person p3("ccc", 30);
	Person p4("ddd", 40);
	Person p5("eee", 50);
	Person p6("fff", 60);
 
	v.push_back(&p1);
	v.push_back(&p2);
	v.push_back(&p3);
	v.push_back(&p4);
	v.push_back(&p5);
	v.push_back(&p6);
 
	for (vector <Person*>::iterator it = v.begin(); it != v.end(); it++) {
		Person* p = (*it);
		cout << "Name= " << p->mName << "Age= " << p->mAge << endl;
		cout << "Name= " << (*it)->mName << "Age= " << (*it)->mAge << endl;//两者相同
	}
}
int main() {
	test01();
	test02();
}

7.1.3 容器嵌套容器

7.2 string容器

7.2.1 基本概念

  • char* 是一个指针
  • string是一个类,类封装了char*,管理这个字符串,是一个char*型的容器
  • 特点:string类内部封装了很多成员方法

7.2.2 构造函数

构造函数原型

//1,默认构造
string s1;
//2,string(const char* s);
const char* str;
string s2(str)="hello word!";
//3,string(const string& str);
string s3(s2);
//,sring(int n,char c);
string s4(10,`a`);

7.2.3 赋值操作

//- 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 str5;`
str5.assign("hello C++", 5);`
cout << "str5 = " << str5 << endl;`
 
`string str7;`
str7.assign(10, 'w');`
cout << "str7 = " << str7 << endl;`

7.2.4 字符串的拼接

函数原型:

  • string& operator+=(const char* str); //重载+=操作符
  • string& operator+=(const char c); //重载+=操作符
  • string& operator+=(const string& str); //重载+=操作符
  • string& append(const char *s); //把字符串s连接到当前字符串结尾
  • string& append(const char *s, int n); //把字符串s的前n个字符连接到当前字符串结尾
  • string& append(const string &s); //同operator+=(const string& str)
  • string& append(const string &s, int pos, int n);//字符串s中从pos开始的n个字符连接到字符串结尾
	string str1 = "我";
	str1 += "爱玩游戏";
 
	string str3 = "I";
	str3.append(" love ");
	str3.append("game abcde", 4);
	//str3.append(str2);
	str3.append(str2, 4, 3); // 从下标4位置开始 ,截取3个字符,拼接到字符串末

7.2.5 查找与替换

函数原型: 略

    string str1 = "abcdefg";
	int pos = str1.find("de");	pos = str1.rfind("de");
 
	string str1 = "abcdefg";
	str1.replace(1, 3, "1111");
	//a1111efg

7.2.6 字符串比较

比较方式:

  • 字符串比较是按字符的ASCII码进行对比

函数原型: 略

string s1 = "hello";
	string s2 = "aello";
 
	int ret = s1.compare(s2);
 
	if (ret == 0) {
		cout << "s1 等于 s2" << endl;
	}
	else if (ret > 0)
	{
		cout << "s1 大于 s2" << endl;
	}
	else
	{
		cout << "s1 小于 s2" << endl;
	}

7.2.7 字符存取

函数原型: 略

`str[i]==str.at(i)`

7.2.8 插入和删除

函数原型: 略

	string str = "hello";
	str.insert(1, "111");
 
	str.erase(1, 3);  //从1号位置开始3个字符
}

7.2.9 子串

函数原型: 略

	string str = "abcdefg";
	string subStr = str.substr(1, 3);
	//bcd
	string email = "hello@sina.com";
	int pos = email.find("@");
	string username = email.substr(0, pos);
	cout << "username: " << username << endl;

7.3 vector容器

7.3.1 构造函数

void printVector(vector<int>& v) {
 
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}
 
void test01()
{
	vector<int> v1; //无参构造
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printVector(v1);
 
	vector<int> v2(v1.begin(), v1.end());
	printVector(v2);//通过区间方式进行构造
 
	vector<int> v3(10, 100);
	printVector(v3);//10个100
	
	vector<int> v4(v3);
	printVector(v4);
}

7.3.2 赋值操作

vector<int> v1; //无参构造
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printVector(v1);
 
	vector<int>v2;
	v2 = v1;
	printVector(v2);// =
 
	vector<int>v3;
	v3.assign(v1.begin(), v1.end());
	printVector(v3);//assign
 
	vector<int>v4;
	v4.assign(10, 100);
	printVector(v4);

7.3.2 容量和大小

  • empty(); //判断容器是否为空
  • capacity(); //容器的容量
  • size(); //返回容器中元素的个数
  • resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除。
  • resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除

7.3.3 插入与删除

	vector<int> v1;
	//尾插
	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);
	printVector(v1);
	//尾删
	v1.pop_back();
	printVector(v1);
	//插入
	v1.insert(v1.begin(), 100);
	printVector(v1);
 
	v1.insert(v1.begin(), 2, 1000);
	printVector(v1);
 
	//删除
	v1.erase(v1.begin());
	printVector(v1);
 
	//清空
	v1.erase(v1.begin(), v1.end());
	v1.clear();
	printVector(v1);

7.3.4 数据存取

	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;
 
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1.at(i) << " ";
	}
	cout << endl;
 
	cout << "v1的第一个元素为: " << v1.front() << endl;
	cout << "v1的最后一个元素为: " << v1.back() << endl;

7.3.5 互换容器

	vector<int> v;
	for (int i = 0; i < 100000; i++) {
		v.push_back(i);
	}
 
	cout << "v的容量为:" << v.capacity() << endl;
	cout << "v的大小为:" << v.size() << endl;
 
	v.resize(3);
 
	cout << "v的容量为:" << v.capacity() << endl;
	cout << "v的大小为:" << v.size() << endl;
 
	//收缩内存
	vector<int>(v).swap(v); //匿名对象
 
	cout << "v的容量为:" << v.capacity() << endl;
	cout << "v的大小为:" << v.size() << endl;

7.3.6 预留空间

函数原型:

  • reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问。

7.4 deque容器

7.4.1 构造函数

函数原型:

  • deque<T> deqT; //默认构造形式
  • deque(beg, end); //构造函数将[beg, end)区间中的元素拷贝给本身。
  • deque(n, elem); //构造函数将n个elem拷贝给本身。
  • deque(const deque &deq); //拷贝构造函数
void printDeque(const deque<int>& d) 
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
		cout << *it << " ";
 
	}
	cout << endl;
}//迭代器中的const用法
//deque构造
void test01() {
 
	deque<int> d1; //无参构造函数
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	printDeque(d1);
	deque<int> d2(d1.begin(),d1.end());
	printDeque(d2);
 
	deque<int>d3(10,100);
	printDeque(d3);
 
	deque<int>d4 = d3;
	printDeque(d4);
}

7.4.2 赋值操作

	deque<int>d3;
	d3.assign(d1.begin(), d1.end());
	printDeque(d3);
 
	deque<int>d4;
	d4.assign(10, 100);
	printDeque(d4);

7.4.3 大小操作

函数原型:

  • deque.empty(); //判断容器是否为空

  • deque.size(); //返回容器中元素的个数

  • deque.resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除。

  • deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除。

  • 没有容量概念

7.4.4 插入和删除

函数原型:

两端插入操作:

  • push_back(elem); //在容器尾部添加一个数据
  • push_front(elem); //在容器头部插入一个数据
  • pop_back(); //删除容器最后一个数据
  • pop_front(); //删除容器第一个数据

指定位置操作:

  • insert(pos,elem); //在pos位置插入一个elem元素的拷贝,返回新数据的位置。
  • insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值。
  • insert(pos,beg,end); //在pos位置插入[beg,end)区间的数据,无返回值。
  • clear(); //清空容器的所有数据
  • erase(beg,end); //删除[beg,end)区间的数据,返回下一个数据的位置。
  • erase(pos); //删除pos位置的数据,返回下一个数据的位置。

总结:

  • 插入和删除提供的位置是迭代器!
  • 尾插 --- push_back
  • 尾删 --- pop_back
  • 头插 --- push_front
  • 头删 --- pop_front

7.4.5 数据存取

函数原型:

  • at(int idx); //返回索引idx所指的数据
  • operator[]; //返回索引idx所指的数据
  • front(); //返回容器中第一个数据元素
  • back(); //返回容器中最后一个数据元素

7.4.6 排序

功能描述:

  • 利用算法实现对deque容器进行排序

算法:

  • sort(iterator beg, iterator end) //对beg和end区间内元素进行排序

7.4.7 STL 案例1-评委打分

7.5 stack容器

7.5.1 构造函数:

  • stack<T> stk; //stack采用模板类实现, stack对象的默认构造形式
  • stack(const stack &stk); //拷贝构造函数

7.5.2 赋值操作:

  • stack& operator=(const stack &stk); //重载等号操作符

7.5.3 数据存取:

  • push(elem); //向栈顶添加元素
  • pop(); //从栈顶移除第一个元素
  • top(); //返回栈顶元素

7.5.4 大小操作:

  • empty(); //判断堆栈是否为空
  • size(); //返回栈的大小

7.6 queue容器

7.6.1 构造函数:

  • queue<T> que; //queue采用模板类实现,queue对象的默认构造形式
  • queue(const queue &que); //拷贝构造函数

7.6.2 赋值操作:

  • queue& operator=(const queue &que); //重载等号操作符

7.6.3 数据存取:

  • push(elem); //往队尾添加元素
  • pop(); //从队头移除第一个元素
  • back(); //返回最后一个元素
  • front(); //返回第一个元素

7.6.4 大小操作:

  • empty(); //判断堆栈是否为空
  • size(); //返回栈的大小

7.7 list容器

7.7.1 构造函数

**函数原型:**
  • list<T> lst; //list采用采用模板类实现,对象的默认构造形式:
  • list(beg,end); //构造函数将[beg, end)区间中的元素拷贝给本身。
  • list(n,elem); //构造函数将n个elem拷贝给本身。
  • list(const list &lst); //拷贝构造函数。

7.7.2 赋值与交换

**函数原型:**
  • assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。
  • assign(n, elem); //将n个elem拷贝赋值给本身。
  • list& operator=(const list &lst); //重载等号操作符
  • swap(lst); //将lst与本身的元素互换。

7.7.3 大小操作

**函数原型:**
  • size(); //返回容器中元素的个数

  • empty(); //判断容器是否为空

  • resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除。

  • resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。

       //如果容器变短,则末尾超出容器长度的元素被删除。
    

7.7.4 插入和删除

list<int> L;
	//尾插
	L.push_back(10);
	L.push_back(20);
	L.push_back(30);
	//头插
	L.push_front(100);
	L.push_front(200);
	L.push_front(300);
    //300 200 100 10 20 30
	printList(L);
 
	//尾删
	L.pop_back();
	printList(L);
	//头删
	L.pop_front();
	printList(L);
 
	//插入(迭代器)
	list<int>::iterator it = L.begin();
	L.insert(++it, 1000);
	printList(L);
	//删除(迭代器)
	it = L.begin();
	L.erase(++it);
	printList(L);
 
	//移除(按值删除)
	L.push_back(10000);
	L.push_back(10000);
	L.push_back(10000);//增加三个“10000”
	printList(L);
	L.remove(10000);//全删
	printList(L);
    
    //清空
	L.clear();
	printList(L);

7.7.5 数据存取

**函数原型:**
  • front(); //返回第一个元素。

  • back(); //返回最后一个元素。

  • 不可用at ,[]表示

7.7.6 反转与排序

**函数原型:**
  • reverse(); //反转链表
  • sort(); //链表排序
  • //所有不支持随机访问迭代器的容器,不可以用标准算法
  • 但内部会提供一些算法

排序案例

class Person {
public:
	Person(string name, int age , int height) {
		m_Name = name;
		m_Age = age;
		m_Height = height;
	}
 
public:
	string m_Name;  //姓名
	int m_Age;      //年龄
	int m_Height;   //身高
};
 
 
bool ComparePerson(Person& p1, Person& p2) {
 
	if (p1.m_Age == p2.m_Age) {
		return p1.m_Height  > p2.m_Height;
	}
	else
	{
		return  p1.m_Age < p2.m_Age;
	}
 
}
 
void test01() {
 
	list<Person> L;
 
	Person p1("刘备", 35 , 175);
	Person p2("曹操", 45 , 180);
	Person p3("孙权", 40 , 170);
	Person p4("赵云", 25 , 190);
	Person p5("张飞", 35 , 160);
	Person p6("关羽", 35 , 200);
 
	L.push_back(p1);
	L.push_back(p2);
	L.push_back(p3);
	L.push_back(p4);
	L.push_back(p5);
	L.push_back(p6);
 
	for (list<Person>::iterator it = L.begin(); it != L.end(); it++) {
		cout << "姓名: " << it->m_Name << " 年龄: " << it->m_Age 
              << " 身高: " << it->m_Height << endl;
	}
 
	cout << "---------------------------------" << endl;
	L.sort(ComparePerson); //排序
 
	for (list<Person>::iterator it = L.begin(); it != L.end(); it++) {
		cout << "姓名: " << it->m_Name << " 年龄: " << it->m_Age 
              << " 身高: " << it->m_Height << endl;
	}
}

7.8 set/multiset容器

  • multiset可以插入重复的数据

7.8.1 构造与赋值

set<int> s1;
 
	s1.insert(10);
	s1.insert(30);
	s1.insert(20);
	s1.insert(40);
	printSet(s1);
 
	//拷贝构造
	set<int>s2(s1);
	printSet(s2);
 
	//赋值
	set<int>s3;
	s3 = s2;
	printSet(s3);

7.8.2 大小与交换

函数原型:

  • size(); //返回容器中元素的数目
  • empty(); //判断容器是否为空
  • swap(st); //交换两个集合容

7.8.3 插入和删除

函数原型:

  • insert(elem); //在容器中插入元素。
  • clear(); //清除所有元素
  • erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。
  • erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
  • erase(elem); //删除容器中值为elem的元素。

7.8.4 查找和统计

函数原型:

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
  • count(key); //统计key的元素个数
	set<int> s1;
	//插入
	s1.insert(10);
	s1.insert(30);
	s1.insert(20);
	s1.insert(40);
	
	//查找
	set<int>::iterator pos = s1.find(30);//用迭代器接住find的位置
 
	if (pos != s1.end())//迭代器对比
	{
		cout << "找到了元素 : " << *pos << endl;//对迭代器的解引用
	}
	else
	{
		cout << "未找到元素" << endl;
	}

7.8.5 pair对组创建

	pair<string, int> p(string("Tom"), 20);
	cout << "姓名: " <<  p.first << " 年龄: " << p.second << endl;
 
	pair<string, int> p2 = make_pair("Jerry", 10);
	cout << "姓名: " << p2.first << " 年龄: " << p2.second << endl;

7.8.6 排序

class MyCompare 
{
public:
	bool operator()(int v1, int v2) {
		return v1 > v2;
	}
};
void test01() 
{    
	set<int> s1;
	s1.insert(10);
	s1.insert(40);
	s1.insert(20);
	s1.insert(30);
	s1.insert(50);
 
	//默认从小到大
	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
 
	//指定排序规则
	set<int,MyCompare> s2;
	s2.insert(10);
	s2.insert(40);
	s2.insert(20);
	s2.insert(30);
	s2.insert(50);
 
	for (set<int, MyCompare>::iterator it = s2.begin(); it != s2.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

自定义数据类型排序

class comparePerson
{
public:
	bool operator()(const Person& p1, const Person &p2)
	{
		//按照年龄进行排序  降序
		return p1.m_Age > p2.m_Age;
	}
};

7.9 map/multimap容器

7.9.1 构造与赋值

void printMap(map<int,int>&m)
{
	for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key = " << it->first << " value = " << it->second << endl;
	}
	cout << endl;
}
 
void test01()
{
	map<int,int>m; //默认构造
	m.insert(pair<int, int>(1, 10));
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));
	printMap(m);
 
	map<int, int>m2(m); //拷贝构造
	printMap(m2);
 
	map<int, int>m3;
	m3 = m2; //赋值
	printMap(m3);
}

7.9.2 大小与交换

函数原型:

  • size(); //返回容器中元素的数目
  • empty(); //判断容器是否为空
  • swap(st); //交换两个集合容器

7.9.3 插入和删除

//插入
	map<int, int> m;
	//第一种插入方式
	m.insert(pair<int, int>(1, 10));
	//第二种插入方式
	m.insert(make_pair(2, 20));
	//第三种插入方式
	m.insert(map<int, int>::value_type(3, 30));
	//第四种插入方式
	m[4] = 40; 
	printMap(m);
 
	//删除
	m.erase(m.begin());
	printMap(m);
 
	m.erase(3);//按照key删除
	printMap(m);
 
	//清空
	m.erase(m.begin(),m.end());
	m.clear();
	printMap(m);

7.9.4 查找和统计

函数原型:

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
  • count(key); //统计key的元素个数

7.9.5 排序

class MyCompare {
public:
	bool operator()(int v1, int v2) {
		return v1 > v2;
	}
};
 
void test01() 
{
	//默认从小到大排序
	//利用仿函数实现从大到小排序
	map<int, int, MyCompare> m;
 
	m.insert(make_pair(1, 10));
	m.insert(make_pair(2, 20));
	m.insert(make_pair(3, 30));
	m.insert(make_pair(4, 40));
	m.insert(make_pair(5, 50));
 
	for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) {
		cout << "key:" << it->first << " value:" << it->second << endl;
	}

7.8.10 STL案例2

8. STL - 函数对象

8.1 函数对象

概念:

  • 重载函数调用操作符的类,其对象常称为函数对象
  • 函数对象使用重载的()时,行为类似函数调用,也叫仿函数

本质:

函数对象(仿函数)是一个,不是一个函数

#include <string>
 
//1、函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值
class MyAdd
{
public :
	int operator()(int v1,int v2)
	{
		return v1 + v2;
	}
};
 
void test01()
{
	MyAdd myAdd;
	cout << myAdd(10, 10) << endl;
}
 
//2、函数对象可以有自己的状态
class MyPrint
{
public:
	MyPrint()
	{
		count = 0;
	}
	void operator()(string test)
	{
		cout << test << endl;
		count++; //统计使用次数
	}
 
	int count; //内部自己的状态
};
void test02()
{
	MyPrint myPrint;
	myPrint("hello world");
	myPrint("hello world");
	myPrint("hello world");
	cout << "myPrint调用次数为: " << myPrint.count << endl;
}
 
//3、函数对象可以作为参数传递
void doPrint(MyPrint &mp , string test)
{
	mp(test);
}
 
void test03()
{
	MyPrint myPrint;
	doPrint(myPrint, "Hello C++");
}
 

8.2 谓词

概念:

  • 返回bool类型的仿函数称为谓词
  • 如果operator()接受一个参数,那么叫做一元谓词
  • 如果operator()接受两个参数,那么叫做二元谓词
//1.一元谓词
//仿函数,返回值类型是bool的数据类型称为谓词
struct GreaterFive{
	bool operator()(int val) {
		return val > 5;
	}
};
 
void test01() {
 
	vector<int> v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
 
	vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());//find—_if语法(f,l,bool)
	if (it == v.end()) {
		cout << "没找到!" << endl;
	}
	else {
		cout << "找到:" << *it << endl;
	}
 
}
#include <vector>
#include <algorithm>
//二元谓词
class MyCompare
{
public:
	bool operator()(int num1, int num2)
	{
		return num1 > num2;
	}
};
 
void test01()
{
	vector<int> v;
	v.push_back(10);
	v.push_back(40);
	v.push_back(20);
	v.push_back(30);
	v.push_back(50);
 
	//默认从小到大
	sort(v.begin(), v.end());
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	cout << "----------------------------" << endl;
 
	//使用函数对象改变算法策略,排序从大到小
	sort(v.begin(), v.end(), MyCompare());
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

8.3 内建函数对象

概念:

  • STL内建了一些函数对象

分类:

  • 算术仿函数
  • 关系仿函数
  • 逻辑仿函数

用法:

  • 这些仿函数所产生的对象,用法和一般函数完全相同
  • 使用内建函数对象,需要引入头文件 #include<functional>

8.3.1 算术仿函数

功能描述:

  • 实现四则运算
  • 其中negate是一元运算,其他都是二元运算

仿函数原型:

  • template<class T> T plus<T> //加法仿函数
  • template<class T> T minus<T> //减法仿函数
  • template<class T> T multiplies<T> //乘法仿函数
  • template<class T> T divides<T> //除法仿函数
  • template<class T> T modulus<T> //取模仿函数
  • template<class T> T negate<T> //取反仿函数
void test01()
{
	negate<int> n;
	cout << n(50) << endl;
}
 
//plus
void test02()
{
	plus<int> p;
	cout << p(10, 20) << endl;
}

8.3.2 关系仿函数

功能描述:

  • 实现关系对比

仿函数原型:

  • template<class T> bool equal_to<T> //等于
  • template<class T> bool not_equal_to<T> //不等于
  • template<class T> bool greater<T> //大于
  • template<class T> bool greater_equal<T> //大于等于
  • template<class T> bool less<T> //小于
  • template<class T> bool less_equal<T> //小于等于
//自己实现仿函数
	//sort(v.begin(), v.end(), MyCompare());
	//STL内建仿函数  大于仿函数
	sort(v.begin(), v.end(), greater<int>());

8.3.3 逻辑仿函数

功能描述:

  • 实现逻辑运算

函数原型:

  • template<class T> bool logical_and<T> //逻辑与
  • template<class T> bool logical_or<T> //逻辑或
  • template<class T> bool logical_not<T> //逻辑非
	vector<bool> v;
	v.push_back(true);
	v.push_back(false);
	v.push_back(true);
	v.push_back(false);
	//1010
 
	for (vector<bool>::iterator it = v.begin();it!= v.end();it++)
	{
		cout << *it << " ";
	}
	cout << endl;
 
	//逻辑非  将v容器搬运到v2中,并执行逻辑非运算
	vector<bool> v2;
	v2.resize(v.size());
	transform(v.begin(), v.end(),  v2.begin(), logical_not<bool>());
	for (vector<bool>::iterator it = v2.begin(); it != v2.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	//0101

9. STL - 常用算法

概述:

  • 算法主要是由头文件<algorithm> <functional> <numeric>组成。

  • <algorithm>是所有STL头文件中最大的一个,范围涉及到比较、 交换、查找、遍历操作、复制、修改等等

  • <numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数

  • <functional>定义了一些模板类,用以声明函数对象。

9.1 常用遍历算法

算法简介:

  • for_each //遍历容器
  • transform //搬运容器到另一个容器中

9.1.1 for_each算法(最常见)

#include <algorithm>
#include <vector>
 
//普通函数
void print01(int val) 
{
	cout << val << " ";
}
//函数对象
class print02 
{
 public:
	void operator()(int val) 
	{
		cout << val << " ";
	}
};
 
//for_each算法基本用法
void test01() {
 
	vector<int> v;
	for (int i = 0; i < 10; i++) 
	{
		v.push_back(i);
	}
 
	//遍历算法
	for_each(v.begin(), v.end(), print01);
	cout << endl;
 
	for_each(v.begin(), v.end(), print02());
	cout << endl;
}

9.1.2 transform算法

#include<vector>
#include<algorithm>
 
//常用遍历算法  搬运 transform
 
class TransForm//内部还可以做一些逻辑运算
{
public:
	int operator()(int val)
	{
		return val;
	}
 
};
 
class MyPrint
{
public:
	void operator()(int val)
	{
		cout << val << " ";
	}
};
 
void test01()
{
	vector<int>v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
 
	vector<int>vTarget; //目标容器
 
	vTarget.resize(v.size()); // 目标容器需要提前开辟空间
 
	transform(v.begin(), v.end(), vTarget.begin(), TransForm());
 
	for_each(vTarget.begin(), vTarget.end(), MyPrint());
}
 

9.2 常用查找算法

算法简介:

  • find //查找元素
  • find_if //按条件查找元素
  • adjacent_find //查找相邻重复元素
  • binary_search //二分查找法
  • count //统计元素个数
  • count_if //按条件统计元素个数

9.2.1 find算法

void test01() {
 
	vector<int> v;
	for (int i = 0; i < 10; i++) {
		v.push_back(i + 1);
	}
	//查找容器中是否有 5 这个元素
	vector<int>::iterator it = find(v.begin(), v.end(), 5);
	if (it == v.end()) 
	{
		cout << "没有找到!" << endl;
	}
	else 
	{
		cout << "找到:" << *it << endl;
	}
}
 
class Person {
public:
	Person(string name, int age) 
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	//重载==(用于查找自定义数据类型)
	bool operator==(const Person& p) 
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) 
		{
			return true;
		}
		return false;
	}
 
public:
	string m_Name;
	int m_Age;
};
 
void test02() {
 
	vector<Person> v;
 
	//创建数据
	Person p1("aaa", 10);
	Person p2("bbb", 20);
	Person p3("ccc", 30);
	Person p4("ddd", 40);
 
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
 
	vector<Person>::iterator it = find(v.begin(), v.end(), p2);
	if (it == v.end()) 
	{
		cout << "没有找到!" << endl;
	}
	else 
	{
		cout << "找到姓名:" << it->m_Name << " 年龄: " << it->m_Age << endl;
	}
}

9.2.2 find_if算法

功能描述:

  • 按条件查找元素

函数原型:

  • find_if(iterator beg, iterator end, _Pred); // 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置 // beg 开始迭代器 // end 结束迭代器 // _Pred 函数或者谓词(返回bool类型的仿函数)

9.2.3 adjacent_find算法

功能描述:

  • 查找相邻重复元素

函数原型:

  • adjacent_find(iterator beg, iterator end); // 查找相邻重复元素,返回相邻元素的第一个位置的迭代器 // beg 开始迭代器 // end 结束迭代器

9.2.4 binary_search算法

功能描述:

  • 查找指定元素是否存在

函数原型:

  • bool binary_search(iterator beg, iterator end, value); // 查找指定的元素,查到 返回true 否则false // 注意: 在无序序列中不可用 // beg 开始迭代器 // end 结束迭代器 // value 查找的元素

9.2.5 count算法

功能描述:

  • 统计元素个数

函数原型:

  • count(iterator beg, iterator end, value); // 统计元素出现次数
//自定义数据类型
class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	bool operator==(const Person & p)//重载==号
	{
		if (this->m_Age == p.m_Age)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	string m_Name;
	int m_Age;
};

9.2.6 count_if算法

功能描述:

  • 按条件统计元素个数

函数原型:

  • count_if(iterator beg, iterator end, _Pred); // 按条件统计元素出现次数 // beg 开始迭代器 // end 结束迭代器 // _Pred 谓词
class Greater4
{
public:
	bool operator()(int val)
	{
		return val >= 4;
	}
};
 
//内置数据类型
void test01()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(4);
	v.push_back(5);
	v.push_back(3);
	v.push_back(4);
	v.push_back(4);
 
	int num = count_if(v.begin(), v.end(), Greater4());
 
	cout << "大于4的个数为: " << num << endl;
}
 
//自定义数据类型
class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
 
	string m_Name;
	int m_Age;
};
 
class AgeLess35
{
public:
	bool operator()(const Person &p)
	{
		return p.m_Age < 35;
	}
};
void test02()
{
	vector<Person> v;
 
	Person p1("刘备", 35);
	Person p2("关羽", 35);
	Person p3("张飞", 35);
	Person p4("赵云", 30);
	Person p5("曹操", 25);
 
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	v.push_back(p5);
 
	int num = count_if(v.begin(), v.end(), AgeLess35());
	cout << "小于35岁的个数:" << num << endl;
}

9.3 常用排序算法

学习目标:

  • 掌握常用的排序算法

算法简介:

  • sort //对容器内元素进行排序
  • random_shuffle //洗牌 指定范围内的元素随机调整次序
  • merge // 容器元素合并,并存储到另一容器中
  • reverse // 反转指定范围的元素

9.3.1 sort算法

功能描述:

  • 对容器内元素进行排序

函数原型:

  • sort(iterator beg, iterator end, _Pred); // 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置 // beg 开始迭代器 // end 结束迭代器 // _Pred 谓词
 
	//sort默认从小到大排序
	sort(v.begin(), v.end());
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
 
	//从大到小排序
	sort(v.begin(), v.end(), greater<int>());
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
}

5.3.2 random_shuffle算法

功能描述:

  • 洗牌 指定范围内的元素随机调整次序

函数原型:

  • random_shuffle(iterator beg, iterator end); // 指定范围内的元素随机调整次序 // beg 开始迭代器 // end 结束迭代器

srand((unsigned int)time(NULL)); **总结:**random_shuffle洗牌算法比较实用,使用时记得加随机数种子

5.3.3 merge算法

功能描述:

  • 两个容器元素合并,并存储到另一容器中

函数原型:

  • merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest); // 容器元素合并,并存储到另一容器中 // 注意: 两个容器必须是有序的 // beg1 容器1开始迭代器 // end1 容器1结束迭代器 // beg2 容器2开始迭代器 // end2 容器2结束迭代器 // dest 目标容器开始迭代器

**总结:**merge合并的两个容器必须的有序序列

void test01()
{
	vector<int> v1;
	vector<int> v2;
	for (int i = 0; i < 10 ; i++) 
    {
		v1.push_back(i);
		v2.push_back(i + 1);
	}
 
	vector<int> vtarget;
	//目标容器需要提前开辟空间
	vtarget.resize(v1.size() + v2.size());
	//合并  需要两个有序序列
	merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vtarget.begin());
	for_each(vtarget.begin(), vtarget.end(), myPrint());
	cout << endl;
}

9.3.4 reverse算法

功能描述:

  • 将容器内元素进行反转

函数原型:

  • reverse(iterator beg, iterator end); // 反转指定范围的元素 // beg 开始迭代器 // end 结束迭代器

9.4 常用拷贝和替换算法

学习目标:

  • 掌握常用的拷贝和替换算法

算法简介:

  • copy // 容器内指定范围的元素拷贝到另一容器中
  • replace // 将容器内指定范围的旧元素修改为新元素
  • replace_if // 容器内指定范围满足条件的元素替换为新元素
  • swap // 互换两个容器的元素

9.4.1 copy算法

功能描述:

  • 容器内指定范围的元素拷贝到另一容器中

函数原型:

  • copy(iterator beg, iterator end, iterator dest); // 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置 // beg 开始迭代器 // end 结束迭代器 // dest 目标起始迭代器

9.4.2 replace算法

功能描述:

  • 将容器内指定范围的旧元素修改为新元素

函数原型:

  • replace(iterator beg, iterator end, oldvalue, newvalue); // 将区间内旧元素 替换成 新元素 // beg 开始迭代器 // end 结束迭代器 // oldvalue 旧元素 // newvalue 新元素

**总结:**replace会替换区间内满足条件的元素

9.4.3 replace_if算法

功能描述:

  • 将区间内满足条件的元素,替换成指定元素

函数原型:

  • replace_if(iterator beg, iterator end, _pred, newvalue); // 按条件替换元素,满足条件的替换成指定元素 // beg 开始迭代器 // end 结束迭代器 // _pred 谓词 // newvalue 替换的新元素
class ReplaceGreater30
{
public:
	bool operator()(int val)
	{
		return val >= 30;
	}
 
};

9.4.4 swap算法

功能描述:

  • 互换两个容器的元素

函数原型:

  • swap(container c1, container c2); // 互换两个容器的元素 // c1容器1 // c2容器2

**总结:**swap交换容器时,注意交换的容器要同种类型

9.5 常用算术生成算法

学习目标:

  • 掌握常用的算术生成算法

注意:

  • 算术生成算法属于小型算法,使用时包含的头文件为 #include <numeric>

算法简介:

  • accumulate // 计算容器元素累计总和
  • fill // 向容器中添加元素

5.5.1 accumulate算法

功能描述:

  • 计算区间内 容器元素累计总和

函数原型:

  • accumulate(iterator beg, iterator end, value); // 计算容器元素累计总和 // beg 开始迭代器 // end 结束迭代器 // value 起始值

5.5.2 fill算法

功能描述:

  • 向容器中填充指定的元素

函数原型:

  • fill(iterator beg, iterator end, value); // 向容器中填充元素 // beg 开始迭代器 // end 结束迭代器 // value 填充的值

9.6 常用集合算法

学习目标:

  • 掌握常用的集合算法

算法简介:

  • set_intersection // 求两个容器的交集
  • set_union // 求两个容器的并集
  • set_difference // 求两个容器的差集

9.6.1 set_intersection算法

功能描述:

  • 求两个容器的交集

函数原型:

  • set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

    // 求两个集合的交集 // 注意:两个集合必须是有序序列 // beg1 容器1开始迭代器 // end1 容器1结束迭代器 // beg2 容器2开始迭代器 // end2 容器2结束迭代器 // dest 目标容器开始迭代器

void test01()
{
	vector<int> v1;
	vector<int> v2;
	for (int i = 0; i < 10; i++)
    {
		v1.push_back(i);
		v2.push_back(i+5);
	}
 
	vector<int> vTarget;
	//取两个里面较小的值给目标容器开辟空间
	vTarget.resize(min(v1.size(), v2.size()));
 
	//返回目标容器的最后一个元素的迭代器地址
	vector<int>::iterator itEnd = 
        set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
 
	for_each(vTarget.begin(), itEnd, myPrint());
	cout << endl;
}
  • set_intersection返回值既是交集中最后一个元素的位置

9.6.2 set_union算法

功能描述:

  • 求两个集合的并集

函数原型:

  • set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

    // 求两个集合的并集 // 注意:两个集合必须是有序序列 // beg1 容器1开始迭代器 // end1 容器1结束迭代器 // beg2 容器2开始迭代器 // end2 容器2结束迭代器 // dest 目标容器开始迭代器

  • set_union返回值既是并集中最后一个元素的位置

9.6.3 set_difference算法

功能描述:

  • 求两个集合的差集

函数原型:

  • set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

    // 求两个集合的差集 // 注意:两个集合必须是有序序列 // beg1 容器1开始迭代器 // end1 容器1结束迭代器 // beg2 容器2开始迭代器 // end2 容器2结束迭代器 // dest 目标容器开始迭代器

vector<int> vTarget;
	//取两个里面较大的值给目标容器开辟空间
	vTarget.resize( max(v1.size() , v2.size()));
 
	//返回目标容器的最后一个元素的迭代器地址
	cout << "v1与v2的差集为: " << endl;
	vector<int>::iterator itEnd = 
        set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
	for_each(vTarget.begin(), itEnd, myPrint());
	cout << endl;
 
 
	cout << "v2与v1的差集为: " << endl;
	itEnd = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget.begin());
	for_each(vTarget.begin(), itEnd, myPrint());
	cout << endl;

10. c++案例总结

  1. 基础案例:通讯录管理系统
  2. 提高案例:职工管理系统
  3. 高阶案例:演讲比赛流程管理系统