目录
- 一.数据的输入
- 二.数据的输出
- 三.内存分区模型
- 四.引用
- 五.函数(区别于C语言)
- 六.类和对象
- 七.C++文件操作
- 八.模板
- 九.STL(Standard Template Library标准模板库)
一.数据的输入
- 语法:
cin>>变量
二.数据的输出
- 语法:
cout<<输出项<<endl
- endl相当于\n
- 输出项可以是字符串,也可以是变量
三.内存分区模型
- 意义
- 对不同区域存放的数据赋予不同的生命周期
- 分区
-
代码区:存放函数体的二进制代码,由操作系统进行管理
- 程序执行前出现
- 存放CPU执行的机器指令
- 代码区数据共享(不用反复生成)
- 代码区数据只读(不可修改)
-
全局区:存放全局变量和静态变量以及常量(const修饰的全局常量和字符串常量)
- 程序执行前出现
- 存储全局变量和静态变量和常量
- 程序执行 完后由操作系统释放
-
栈区:由编译器自动分配释放,存放函数的参数值,局部变量,局部常量,形参数据等
- 注意:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
-
如:
#include<iostream> using namespace std; int* func() { int a = 10; return &a;//返回局部变量的地址 } int main() { int* p = func(); cout << *p << endl;//#10 第一次打印正确数字因为编译器替你保留了一次 cout << *p << endl;//#???第二次这个数据就不保留了(visual studio2022编译器会一直保留) system("pause"); return 0; }
-
- 注意:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
-
堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
- 在c++中主要利用new在堆区开辟内存
- 语法:
int *p=new int(10)
int *arr=new int[10]
new int(10)
返回的是开辟的内存的首地址,所以用指针去接收- (10)表示初始值为10
- [10]表示开辟10个元素
- 语法:
- 在c++中主要利用delete在堆区释放内存
- 语法:
delete p
delete[] arr
- p是之前开辟的内存地址,直接delete内存地址即可释放
- 释放数组空间需要加[]
- 语法:
- 在c++中主要利用new在堆区开辟内存
-
四.引用
- 作用:给变量取别名,共用同一个内存空间
- 语法:
数据类型 &别名=原名
- 注意事项
- 引用必须初始化
- 错误:
int &b;
- 错误:
- 引用在初始化后不可以改成别的别名
- 错误:
int &b=a; int &b=c;//更改引用成别的变量的别名会报错
- 错误:
- 引用必须初始化
- 引用形参
- 作用:用形参修饰实参
- 有点:比指针方便
- 函数参数传递对比
-
值传递(形参不修饰实参)
//1.值传递 void val_swap(int a, int b) { int temp = a; a = b; b = temp; } int main() { int a = 10; int b = 20; val_swap(a, b); cout << a << " " << b << endl; system("pause"); return 0; }
-
地址传递(形参修饰实参)
//2.地址传递 void address_swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } int main() { int a = 10; int b = 20; val_swap(&a, &b); cout << a << " " << b << endl; system("pause"); return 0; }
-
引用传递(形参修饰实参)
//3.引用传递 void quote_swap(int &a, int &b) { int temp = a; a = b; b = temp; } int main() { int a = 10; int b = 20; quote_swap(a, b); cout << a << " " << b << endl; system("pause"); return 0; }
-
- 引用做函数返回值
-
作用:作为函数返回值
-
注意:不要返回局部变量的引用
-
代码:
int& test1() { int a = 10; return a; } int main() { int &ref = test1(); cout << ref << endl;//10 cout << ref << endl;//???(但是visual studio 2022编译器永久保留了内存,所以也是10) system("pause"); return 0; }
int& test2() { static int a = 10;//堆区的静态变量 return a; } int main() { int &ref1 = test2(); cout << ref1 << endl;//10 cout << ref1 << endl;//10 test2() = 1000;//左值(作为等号左边) cout << test2() << endl;//1000 a的别名是test2() cout << ref1 << endl;//1000 a的别名是ref1 system("pause"); return 0; }
-
- 引用的本质
-
本质:指针常量(指针的指向不可以修改,指针指向的值是可以改动的)(引用相当于加了一个限制(不可以指向别的地方)的指针)(转换出来的const修饰的是变量名,即地址,所以指向不可以修改)
-
代码:
//引用的本质(编译器自动将引用转化成指针常量形式) void func(int "e)//->void func(int *const quote) { quote = 30;//->*quote=30 } int main() { int a = 10; int "e = a;//->int *const quote=&a quote = 20;//->*quote=20 cout << a << endl; cout << quote << endl;//->cout<<*quote<<endl; func(a);//->func(&a) cout << a << endl; cout << quote << endl;//->cout<<*quote<<endl; //稍后更新引用作为左值的转换 system("pause"); return 0; }
-
- 常量引用
-
本质:(指针的指向不可以修改,指针指向的值是也不可以修改)
-
作用:常量引用主要用来修饰形参,防止形参改变实参
//常量引用 void func(const int& ref) { //无法通过修改ref的值去改变main中的值,防止误操作 //ref = 1000; cout << ref << endl; } int main() { //引用本身需要一个合法的内存空间,所以下面注释掉的这行是错误的,得用下下行 //int& ref = 10; const int &ref = 10;//->const int temp=10;const int &ref=temp; int a = 10; func(a); system("pause"); return 0; }
-
五.函数(区别于C语言)
- 函数默认参数
-
语法:
返回值类型 函数名(参数1,参数2=默认值,参数3=默认值,···){}
-
注意:
- 如果形参列表中某个位置有了默认值,那么这个位置之后所有位置都要先设置默认值
- 如果函数声明有默认参数,函数实现中就不能写默认参数,否则会出现二义性
-
代码:
//函数默认参数 int func(int a, int b = 10, int c = 20) { return a + b + c; } int main() { cout << func(10,30) << endl; system("pause"); return 0; }
-
- 函数占位参数(占位参数也可以有默认参数)
- 语法:
返回值类型 函数名(数据类型){}
返回值类型 函数名(数据类型 = 值){}
- 注意:调用带占位参数的函数需要填补占位参数
- 代码:
//函数占位参数 void func(int a, int) { cout << "不知道有啥用" << endl; } int main() { func(10, 20); system("pause"); return 0; }
- 语法:
- 函数重载
- 作用:函数名可以相同,提高复用性
- 函数重载满足条件:
- 同一个作用域下
- 函数名称相同
- 函数参数类型不同或者参数个数不同或者参数顺序不同
- 注意:
- 函数的返回值不可以进行函数重载
- 形参名字不同不可以进行函数重载
- 代码:
void func() { cout << "func()的调用" << endl; } //参数类型不同 void func(int a) { cout << "func(int a)的调用" << endl; } void func(double a) { cout << "func(double a)的调用"<<endl; } //参数个数不同 void func(int a, double b) { cout << "func(int a, double b)的调用" << endl; } //参数顺序不同 void func(double a, int b) { cout << "func(double a, int b)的调用" << endl; } int main() { func();//第一个函数的调用 func(10);//第二个函数的调用 func(10.0);//第三个函数的调用 func(10, 10.0);//第四个函数的调用 func(10.0, 10);//第五个函数的调用 }
- 代码:
- 引用作为重载条件
-
代码:
//1.引用作为重载的条件 void func(int &a) { cout << "func(int &a)调用" << endl; } void func(const int &a)//引用常量 { cout << "func(const int &a)调用" << endl; } int main() { int a = 0; func(a);//第一个函数被调用 func(0);//第二个函数被调用 system("pause"); return 0; }
-
- 函数重载碰到函数默认参数(写函数重载时尽量不要有默认参数,否则容易出现如下的二义性)
-
代码:
//2.函数重载碰到默认参数 void func(int a,int b=10) { cout << "func(int a,int b=10)调用" << endl; } void func(int a)//引用常量 { cout << "func(int a)调用" << endl; } int main() { //func(10);//这样是调用不了的 func(10, 20);//这样才能调用 system("pause"); return 0; }
-
六.类和对象
-
C++面向对象特性:封装、继承、多态
-
类和结构体的唯一区别
- struct的默认权限为公共,class默认权限为私有
-
封装
- 封装的意义
- 将属性和行为作为一个整体,表现生活中的事物
- 语法:
class 类名 { 访问权限 属性 行为 }; 类名 变量名;
- 语法:
- 将属性和行为加以权限控制
-
访问权限
权限 语法 特点 继承方面特点 公共权限 public 类内可以访问,类外可以访问 保护权限 protected 类内可以访问,类外不可以访问 子类继承父类后可以访问 私有权限 private 类内可以访问,类外不可以访问 子类继承父类后还是不可以访问
-
- 将属性和行为作为一个整体,表现生活中的事物
- 一般通过访问公共成员函数去对私有成员属性进行读写操作
- 优点
- 自己控制读写权限
- 检测用户输入数据是否有效
- 代码:
class Person { public: //可读可写 void setName(string name) { m_Name = name; } string getName() { return m_Name; } //只读 int getAge() { m_Age = 0; return m_Age; } //只写 void setFriend(string Friend) { m_friend = Friend; } private: string m_Name; int m_Age; string m_friend; }; int main() { Person p; p.setName("张三"); cout << p.getName() << endl; cout << p.getAge() << endl; p.setFriend("friend"); system("pause"); return 0; }
- 优点
- 封装的意义
-
对象特性
-
对象的初始化和清理
- 构造函数(自动调用)
- 作用:创建对象时为对象的成员属性赋值
- 语法:
类名(){};
- 特点:
- 无返回值,也不写void
- 构造函数的函数名就是该类的类名
- 构造函数可以有形参,可发生重载
- 在调用对象时系统自动调用且只调用一次
- 需要注意构造函数也有访问权限,如果不声明公共权限,类外创建对象会无法自动调用构造函数,会报错
- 分类:
- 按参数分类:
- 有参构造
- 语法:
类名(数据类型 变量名){};
- 语法:
- 无参构造(默认构造)
- 语法:
类名(){};
- 语法:
- 有参构造
- 按类型分类:
- 普通构造
- 拷贝构造
- 调用时机(黑马P108,没听懂,太难了)
- 使用一个已经创建完毕的对象来初始化一个新对象
- 值传递的方式给函数参数传值
- 以值方式返回局部对象
- 返回的是一个副本对象,与原本对象不在同一个内存空间
- 深拷贝与浅拷贝(如果成员属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题)
-
浅拷贝:简单的赋值拷贝操作(使用指针时先拷贝会指向同一片内存空间,前后两个指针指向同一块内存空间)
-
深拷贝:在堆区重新申请空间,进行拷贝操作(在自己写的拷贝构造函数中重新申请空间)(使用指针时深拷贝会指向别的地方的内存空间,前后两个指针之间没有交集)
-
代码:
#include<iostream> using namespace std; class Person { public: Person() { cout << "默认构造" << endl; } Person(int age,int height) { m_Age = age; m_Height = new int(height);//括号内放的是元素 cout << "有参构造" << endl; } Person(const Person& p) { cout << "深拷贝构造" << endl; m_Age = p.m_Age; //m_Height = p.m_Height;//这是编译器默认实现的代码,是浅拷贝 m_Height = new int(*p.m_Height);//深拷贝 } ~Person() { if (m_Height != NULL) { delete m_Height; m_Height = NULL; } } int m_Age; int *m_Height; }; void test1() { Person p1(10,160); cout << p1.m_Age <<*p1.m_Height<< endl; Person p2(p1); cout << p2.m_Age << *p2.m_Height<<endl; } int main() { test1(); system("pause"); return 0; }
-
- 调用时机(黑马P108,没听懂,太难了)
- 按参数分类:
- 调用方式
- 括号法
-
注意:调用默认构造函数时不要加(),即不要
类名 变量名();
,因为编译器会认为i这是函数的声明; -
代码:
//1.括号法 Person p1(10);//使用有参构造 Person p2(p1);//使用拷贝构造 cout << p1.age << p2.age<<endl;//1010
-
- 显式法
-
注意:
-
类名(实参);
是匿名对象,当前行执行结束后,系统会立即回收掉匿名对象 -
不要利用拷贝构造函数初始化匿名对象,编译器会自动去掉括号认为在定义,就会出现重定义报错
-
代码:
Person p1 = Person(10);//使用有参构造 Person p2 = Person(p1);//使用拷贝构造 Person(10);//匿名对象 对 Person(p1);//错 Person(p2);//错
-
-
代码:
//2.显示法 Person p1 = Person(10);//使用有参构造 Person p2 = Person(p1);//使用拷贝构造
-
- 隐式转换法
-
代码:
//3.隐式转换法 Person p4 = 10;//->Person p4=Person(10)//使用有参构造 Person p5 = p4;//->Person p5=Person(p4)//使用拷贝构造
-
- 括号法
- 析构函数(自动调用)
- 作用:在对象销毁前系统自动调用执行请理工作(将堆区开辟数据做释放)
- 语法:
~类名(){}
- 特点:
- 无返回值,也不写void
- 析构函数的函数名就是~+该类的类名
- 析构函数不可以有形参,所以不可以发生重载
- 在销毁对象前系统自动调用且只调用一次
-
代码:
#include<iostream> using namespace std; class Person { public: //1.构造函数 Person() { cout<<"Person构造函数调用" << endl; } //2.析构函数 ~Person() { cout << "Person析构函数调用" << endl; } }; int main() { Person person;//创建对象后就出现构造调用 system("pause");//按任意键后出现析构调用,因为main函数执行完后销毁了对象 return 0; }
-
调用规则:
- 首先默认情况下编译器至少给一个类添加3个函数:
- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对属性进行值拷贝(参数为:
const 类名 &变量名
)
- 如果用户定义有参构造函数,c++不再提供默认的无参构造,但是会提供默认拷贝(即用户只提供有参,编译器不会提供无参,但提供拷贝)
- 因此如果你只写有参构造,但不写默认构造,然后去调用默认构造编译器会报错
- 如果用户定义拷贝构造函数,c++不会再提供其他构造函数(即用户只提供拷贝,编译器不会提供无参,也不会提供有参)
- 因此如果你只写拷贝构造,但不写默认构造和有参构造,然后去调用默认构造或有参构造编译器会报错
- 首先默认情况下编译器至少给一个类添加3个函数:
- 构造函数(自动调用)
-
初始化列表
-
语法:
构造函数类名():属性1(值1或变量1),属性2(值2或变量2){}
-
代码:
#include<iostream> using namespace std; class Person { public: Person(int a,int b,int c):m_A(a),m_B(b),m_C(c) { ; } int m_A; int m_B; int m_C; }; int main() { Person p(10,20,30); cout << p.m_A << p.m_B << p.m_C << endl; system("pause"); return 0; }
-
-
类对象作为类成员
-
注意:
- 构造顺序:当其他类对象作为本类成员,构造时先构造类对象,再构造自身(先里再外)
- 析构顺序:当其他类对象作为本类成员,析构时先析构自身,再析构类对象(先外再里)
-
代码
#include<iostream> using namespace std; //类对象作为类成员 class Phone { public: Phone() { m_PhoneNum = 12345678901; } long long int m_PhoneNum; }; class Person { public: Phone m_Phone; }; int main() { Person p; cout << p.m_Phone.m_PhoneNum << endl;//12345678901 system("pause"); return 0; }
-
-
静态成员(静态可以理解为共用)
- 定义:在成员变量和成员函数前加上关键字static
- 语法:
static a;
或 - 分类:
- 静态成员变量(全局区)
- 所有对象共享同一份数据
- 在编译阶段分配内存
- 类内声明,类外初始化(类外定义)
- 类内:
static 变量类型 变量名;
- 类外:
变量类型 类名::变量名;
- 表示定义类名作用域下变量名这个静态成员
- 类内:
- 访问方式:
- 通过对象进行访问
- 语法:
类名 变量名;变量名.静态成员变量;
- 语法:
- 通过类名进行访问(类名作用域)
- 语法:
类名::静态成员变量;
- 语法:
- 通过对象进行访问
- 静态成员函数
- 所有对象共享同一个函数
- 静态成员函数只能访问静态成员变量,不可以访问非静态成员变量
- 因为当使用访问方式2去访问时,不知道改变的非静态成员变量是属于哪个对象的
- 访问方式:
- 通过对象进行访问
- 语法:
类名 变量名;变量名.静态成员函数;
- 语法:
- 通过类名进行访问(类名作用域)
- 语法:
类名::静态成员函数;
- 语法:
- 通过对象进行访问
- 静态成员变量(全局区)
- 区别:
- 静态成员函数不需要初始化(定义),和静态成员变量不同
-
C++对象模型和this指针
-
成员变量和成员函数分开存储
-
空对象占用内存空间为1
- C++编译器会给每个空对象分配一个字节空间,是为了区分各个空对象占内存的位置,将它们分隔开(每一个空对象都应该有一个独一无二的空间)
-
除了非静态成员变量属于类的对象,占用正常变量类型的字节,其余(静态成员变量,非静态成员函数,静态成员函数)都不属于类的对象,不占用字节
-
代码
class Person { public: int m_A;//非静态成员变量,属于类的对象上//即属于p//占4字节 static int m_B;//静态成员变量,不属于类的对象上//即不属于p//所以占用字节为0 void func1() {};//非静态成员函数,也是不属于类的对象上//即不属于p//所以占用字节为0//比较特殊 static void func2(){}//静态成员半数,不属于类的对象上//即不属于p//所以占用字节为0 };
-
-
this指针
-
本质:指针常量(this指针指向不可以修改,this指针指向的值是可以修改的)
-
概念:this指针指向被调用的成员函数所属的对象(哪个对象调用了成员函数(得先调用成员函数,才能让this指针指向),this指针就指向谁)
-
用途
- 当形参和成员变量同名时,可以用this指针区分
- 在类的非静态成员函数中返回对象本身,可以用return *this
- 即this指针指向对象,解引用this即可得到对象
-
代码:
#include<iostream> using namespace std; class Person { public: Person(int m_Age) { this->m_Age=m_Age;//this 指向调用了该成员函数的对象p,所以使用p->age去接收形参m_Age } //返回值用引用返回的就是对象本体,指向本身内存,如果不用引用返回的是对象副本,与对象没有关系,后续的操作就改变不了对象 Person &PersonAdd(Person& p)//不懂这里的返回值为什么是Person &,不能是Person或Person * { this->m_Age += p.m_Age; //this是指向调用了这个函数的对象,在这里是p3 return *this; } int m_Age; }; //1.解决名称冲突 void test1() { Person p1(10); cout << p1.m_Age << endl;//10 } //2.返回对象本身用*this void test2() { Person p2(1); Person p3(2); //链式编程思想//cout<< <<也是链式编程思想 p3.PersonAdd(p2).PersonAdd(p2);//2+1+1//如果使用Person PersonAdd(p2)则这个地方会调用p3的默认拷贝构造函数,返回的是一个新副本,与p3不在同一个内存空间 cout << p3.m_Age << endl;//4 } int main() { test1(); test2(); system("pause"); return 0; }
-
-
空指针访问成员函数
-
注意:有没有用到this指针,如果用来this指针就要加判断保证代码的健壮性
-
代码:
#include<iostream> using namespace std; //空指针调用成员函数 class Person { public: void showName() { cout << "Name" << endl; } void showAge() { if(this==NULL)//不懂这里为什么不是*this==NULL { return; } cout << m_Age<< endl;//这个报错原因是因为默认将m_Age变成this->m_Age,但此时this指向是NULL,所以报错 } int m_Age = 10; }; void test1() { Person *p=NULL;//空指针 p->showName(); p->showAge(); } int main() { test1(); system("pause"); return 0; }
-
-
const修饰成员函数
-
常函数:
- 成员函数后加const为常函数
语法:函数返回类型 函数名() const{}
- 常函数内不可以修改成员属性
- 因为this指针(类名 *const this)(指针常量)变成了(const 类名 *const this)(常指针常量)(此时指针指向的值也不可以修改了)
- 成员属性(成员变量)声明时加关键字mutable后,在常函数中依然可以修改
- 成员函数后加const为常函数
-
常对象(不能通过
对象.成员变量
的方式修改成员变量值,除非成员变量声明时加关键字mutable):- 声明对象前加const称该对象为常对象
- 常对象只能调用常函数
-
代码:
#include<iostream> using namespace std; //常函数 class Person { public: void showPerson() const { //this->m_A = 100;//让指针指向的值也不可以改变 this->m_B = 100;//成员变量加mutable关键字后可以修改 } void func() { } int m_A; mutable int m_B;//特殊变量,加上关键字mutable后,即使在常函数中,也可以修改这个值 }; int main() { const Person p2;//常对象 //p2.m_A=10;//报错//常对象不能修改成员属性值,除非成员变量声明时前面加mutable p2.m_B = 10; //常对象只能调用常函数 p2.showPerson(); //p2.func();//报错//常对象不可以调用普通成员函数,因为普通成员函数可以修改成员属性值,而常对象定义就是不能修改成员属性值 system("pause"); return 0; }
-
-
-
-
友元
- 关键字:friend
- 目的:让类外特殊的一些函数或者类访问改类中的私有成员
- 友元的三种实现:
- 全局函数做友元
-
语法:在类中写
friend 函数声明
即可在类外使用该函数对类中的私有属性进行访问 -
代码:
#include<iostream> #include <string> using namespace std; class Building { //friend 加上这一句函数声明即可在类外使用该函数去访问私有属性 friend void goodGay(Building &building); public: Building() { m_SittingRoom = "客厅"; m_BedRoom = "卧室"; } string m_SittingRoom;//客厅 private: string m_BedRoom;//卧室 }; //全局函数 void goodGay(Building &building) { cout << building.m_SittingRoom << endl; cout << building.m_BedRoom << endl; } void test1() { Building b; goodGay(b); } int main() { test1(); system("pause"); return 0; }
-
- 类做友元
-
语法:在类1中写
friend 类2声明
即可使用类2中的所有成员函数去访问类1的私有属性 -
代码:
#include<iostream> #include<string> using namespace std; //类做友元 class Building;//类声明 class GoodGay { public: GoodGay();//先在类内声明 void visit();//先在类内声明 Building *b; }; class Building { friend class GoodGay;//友元+类声明后可以使用该类去访问给出友元的类的私有属性 public: Building();//先在类内声明 string m_SittingRoom; private: string m_BedRoom; }; //再在类外写成员函数,需要声明在该类域下 GoodGay::GoodGay() { b = new Building; } void GoodGay::visit() { cout << b->m_SittingRoom << endl; cout << b->m_BedRoom << endl;//使用友元访问私有属性 } //再在类外写成员函数,需要声明在该类域下 Building::Building() { m_SittingRoom = "客厅"; m_BedRoom = "卧室"; }; void test1() { GoodGay g; g.visit(); } int main() { test1(); system("pause"); return 0; }
-
- 成员函数做友元
-
语法:在类1中写
friend 成员函数返回类型 类2名字::成员函数名();
即可使用类2中的该成员函数去访问类1的私有属性 -
代码:
#include<iostream> #include<string> using namespace std; class Building; class GoodGay { public: GoodGay(); void visit();//让visit函数可以访问Building中私有成员 Building *b; }; class Building { friend void GoodGay::visit();//GoodGay类下的visit函数作为Building类的友元可以访问Building类的私有属性 public: Building(); string m_SittingRoom; private: string m_BedRoom; }; Building::Building() { m_SittingRoom = "客厅"; m_BedRoom = "卧室"; } GoodGay::GoodGay() { b = new Building; } void GoodGay::visit() { cout << b->m_SittingRoom << endl; cout << b->m_BedRoom << endl; } void test() { GoodGay g; g.visit(); } int main() { test(); system("pause"); return 0; }
-
- 全局函数做友元
-
类外写成员函数
-
代码:
class Building; class GoodGay { public: GoodGay();//先在类内声明 void visit();//先在类内声明 Building *b; }; class Building { public: Building();//先在类内声明 string m_SittingRoom; private: string m_BedRoom; }; //再在类外写成员函数,需要声明在该类域下 GoodGay::GoodGay() { b = new Building; } void GoodGay::visit() { cout << b->m_SittingRoom << endl; } //再在类外写成员函数,需要声明在该类域下 Building::Building() { m_SittingRoom = "客厅"; m_BedRoom = "卧室"; };
-
-
运算符重载
- 运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
- 注意:
- 编译器会自动简化运算符
- 运算符重载也可以发生函数重载
- 对于内置的数据类型的表达式的运算符是不可能改变的,比如(1+1=2,float,int等数据类型),自定义的数据类型才可以改变
- 不要滥用运算符重载
- *使用链式编程时:链式编程需要返回自身对象(this);返回类型需要用引用(类型 &),否则只能返回副本
- 常用:成员函数和全局函数进行运算符重载
- 分类:
- 加号运算符重载
-
关键:
operator<<
-
作用:实现两个自定义数据类型相加的运算
-
代码:
#include<iostream> using namespace std; //加号运算符重载 //1.成员函数重载+号 class Person1 { public: Person1() { m_A = 10; m_B = 20; } Person1 operator+(Person1& p) { Person1 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; }; void test1() { Person1 p1; Person1 p2; Person1 p3 = p1+p2;//被编译器简化了,原本应该写成Person1 p3 = p1.operator+(p2); cout << p3.m_A << " " << p3.m_B << endl;//20 40 } //2.全局函数重载+号 class Person2 { public: Person2() { m_A = 10; m_B = 20; } int m_A; int m_B; }; Person2 operator+(Person2 &p1, Person2 &p2) { Person2 temp; temp.m_A = p1.m_A + p2.m_A; temp.m_B = p1.m_B + p2.m_B; return temp; } void test2() { Person2 p1; Person2 p2; Person2 p3 = p1 + p2;//被编译器简化了,原本应该写成Person2 p3 = operator+(p1,p2); cout << p3.m_A << " " << p3.m_B << endl;//20 40 } //3.全局函数使用函数重载+号 class Person3 { public: Person3() { m_A = 10; m_B = 20; } int m_A; int m_B; }; Person3 operator+(Person3& p1, int num) { Person3 temp; temp.m_A = p1.m_A + num; temp.m_B = p1.m_B + num; return temp; } void test3() { Person3 p1; Person3 p3 = p1 + 100;//被编译器简化了,原本应该写成Person3 p3 = operator+(p1,100); cout << p3.m_A << " " << p3.m_B << endl;//110 120 } int main() { test1(); test2(); test3(); system("pause"); return 0; }
-
- 左移运算符重载
-
关键:
operator<<
-
作用:自定义<<
-
注意:
- 一般不用成员函数进行左移运算符重载,而是使用全局函数
- 重载左移运算符配合友元可以实现输出自定义数据类型
-
代码:
#include<iostream> using namespace std; 1.成员函数重载左移运算符 //class Person1 //{ //public: // Person1() // { // m_A = 10; // m_B = 20; // } // //通常不会利用成员函数重载<<运算符,因为无法实现cout在左侧 // //p.operator<<cout 简化:p<<cout // //void operator<<(cout) // //{ // // //} // int m_A; // int m_B; //}; // //void test1() //{ // Person1 p1; // cout << p1 << endl; //} //2.成员函数重载左移运算符 class Person2 { friend ostream& operator<<(ostream& cout, Person2& p2);//简化为 cout<<p public: Person2() { m_A = 10; m_B = 20; } private: int m_A; int m_B; }; ostream &operator<<(ostream &cout, Person2 &p2)//简化为 cout<<p { cout << "m_A=" << p2.m_A << "m_B=" << p2.m_B ; return cout; } void test2() { Person2 p2; cout << p2<<"hi" << endl;//可是这时用了endl后时传参给p2吗,好奇怪//因为这里发生了函数重载,endl或者"hi"的类型和Person2不同,所以不会调用自定义左移运算符,而是用系统自带的 } int main() { //test1(); test2(); system("pause"); return 0; }
-
- 递增运算符重载
-
关键:
- 前置递增:
operator++()
- 后置递增:
operator++(int)
- 前置递增:
-
作用:通过重载递增运算符,实现自己的整型数据
-
注意:
- 前置递增需要返回引用
- 后置递增不能返回引用(因为是局部对象,函数执行完后会被释放掉),要返回值
-
代码:
#include<iostream> using namespace std; //重载递增运算符 //自定义整形 class MyInteger { friend ostream &operator<<(ostream& cout, MyInteger myint); public: MyInteger() { m_Num = 0; } //重载前置++运算符//不需要传参 MyInteger &operator++()//返回类型得用引用,不用引用的话只是副本//返回引用是为了一直对一个数据进行递增操作 { this->m_Num++;//先自身做加加运算 return *this;//再对自身做一个返回 } //重载后置++运算符 MyInteger operator++(int)//int(也只能用int)代表占位参数,可以用于区分前置递增运算符和后置递增运算符//不能返回引用,因为函数执行完后temp会被释放掉,需要一个副本 { //先 记录此时的结果 MyInteger temp = *this;//temp是局部对象,不能返回引用,因为函数执行完后temp会被释放掉 //后 让自身的值++ this->m_Num++; //最后将之前记录的结果返回 return temp; } private: int m_Num; }; //重载<<运算符 ostream &operator<<(ostream& cout, MyInteger myint) { cout << myint.m_Num; return cout; } void test1() { MyInteger myint; cout << ++myint << endl; } void test2() { MyInteger myint; cout << (myint++)++ << endl; cout << myint << endl; } int main() { //test1(); test2(); system("pause"); return 0; }
-
- 赋值运算符号重载
-
关键:
operator=
-
c++编译器至少给一个类加4个函数:
- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对属性进行值拷贝
- 赋值运算符operator=,对属性进行值拷贝
-
注意:
- 如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题
-
代码:
#include<iostream> using namespace std; class Person { public: Person(int age) { m_Age=new int(age); } ~Person() { if (m_Age != NULL) { delete m_Age; m_Age = NULL; } } //重载赋值运算符 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; } int *m_Age; }; void test1() { Person p1(18); Person p2(20); Person p3(30); p3 = p2 = p1;//链式编程需要返回自身对象(*this);返回类型需要用引用(类型 &),否则只能返回副本 cout << "p1的年龄为:" << *p1.m_Age << endl;//18 cout << "p2的年龄为:" << *p2.m_Age << endl;//18 cout << "p3的年龄为:" << *p3.m_Age << endl;//18 } int main() { test1(); system("pause"); return 0; }
-
- 关系运算符重载
-
关键:
- 相等:
operator==
- 不相等:
operator!=
- 相等:
-
作用:重载关系运算符,可以让两个自定义类型对象进行对比操作
-
代码:
#include<iostream> #include<string> using namespace std; //重载关系运算符 class Person { public: Person(string name, int age) { m_Name = name; m_Age = age; } bool operator==(Person &p) { if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) { return true; } else { return false; } } bool operator!=(Person &p) { if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) { return false; } else { return true; } } string m_Name; int m_Age; }; void test1()//重载== { Person p1("a", 10); Person p2("a", 10); if (p1 == p2) { cout << "p1=p2" << endl; } else { cout << "p1!=p2" << endl; } } void test2()//重载!= { Person p1("a", 10); Person p2("b", 10); if (p1 != p2) { cout << "p1!=p2" << endl; } else { cout << "p1==p2" << endl; } } int main() { test1(); test2(); system("pause"); return 0; }
-
- 函数调用运算符重载
-
关键:
operator()()
-
作用:将类作为函数来写,类似python中的__Call__方法,类名()即可调用 函数调用运算符重载 函数
-
注意:
- 函数调用运算符()也可以发生重载
- 由于重载后使用的方式非常像函数的调用,因此称为仿函数
- 仿函数没有固定写法,非常灵活
-
代码:
#include<iostream> #include<string> using namespace std; //输出类 class Myprint { public: //重载函数调用运算符 void operator()(string text) { cout << text << endl; } }; void test1() { Myprint myPrint; myPrint("Hello World");//由于使用起来非常类似于函数调用,因此称为仿函数 } //加法类 class MyAdd { public: int operator()(int a, int b) { return a + b; } }; void test2() { //MyAdd myadd; //cout<<myadd(10, 20) << endl;//30 //匿名函数的对象//MyAdd()创建了匿名对象,然后再调用重载运算符(10,20) cout << MyAdd()(10, 20) << endl;//30 } int main() { test1();//Hello World test2();//30 system("pause"); return 0; }
-
- 加号运算符重载
-
继承
- 继承是面向对象三大特性之一
- 继承的基本语法:
class 子类名:继承方式 父类名{}
- 继承方式
- 公共继承
- 保护继承
- 私有继承
- 示意图
- 父类中私有的内容什么继承方式都访问不到
- 公共继承访问时成员属性访问权限没有变化
- 保护继承访问时除了私有不能访问,其余访问权限都变成保护权限
- 私有继承访问时除了私有不能访问,其余访问权限都变成私有权限
- 子类也称为派生类
- 派生类包含基类成员和本类成员
- 从基类从基类继承过来的表现其共性,而新增的成员体现了其个性
- 父类也称为基类
- 继承方式
- 对象模型
- 父类中所有非静态成员属性都会被子类继承下去
- 父类中私有成员也是被子类继承下去了,只是由编译器给隐藏后访问不到
- 父类中所有非静态成员属性都会被子类继承下去
- 继承中的构造和析构
- 顺序:先构造父类,再构造子类。再析构子类,再析构父类
- 继承同名成员处理方式(即父类和子类同时拥有相同名字的成员)
- 直接访问就可以访问自身的同名成员,父类.成员名就是访问父类的成员,子类.成员名就是访问子类的成员
- 加作用域就可以通过子类去访问父类同名成员
-
注意:
- 如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数(包括父类中重载的),加作用域后就可以访问父类同名函数(包括父类重载的)
-
代码:
#include<iostream> using namespace std; //继承同名成员处理 class A { public: A() { m_A = 100; } void func() { cout << "父类" << endl; } int m_A; }; class B :public A { public: B() { m_A = 200; } void func() { cout << "子类" << endl; } int m_A; }; void test1() { A a; B b; cout << a.m_A << endl;//父类100 cout << b.m_A << endl;//子类200 cout << b.A::m_A << endl;//父类100 } void test2() { A a; a.func();//父类 B b; b.func();//子类 b.A::func();//父类 } int main() { test1(); test2(); system("pause"); return 0; }
- 继承同名静态成员处理方式(和非静态成员处理方式一致)
-
代码:
#include<iostream> using namespace std; //继承同名静态成员处理 class A { public: static void func() { cout << "父类" << endl; } static int m_A; }; int A::m_A = 100; class B :public A { public: static void func() { cout << "子类" << endl; } static int m_A; }; int B::m_A = 200; //属性 void test1() { //1.通过对象来访问数据 cout << "通过对象来访问数据" << endl; A a; B b; cout << a.m_A << endl;//父类100 cout << b.m_A << endl;//子类200 cout << b.A::m_A << endl;//父类100 //2.通过类名来访问数据 cout << "通过类名来访问数据" << endl; cout << A::m_A << endl;//父类100 cout << B::m_A << endl;//子类200 //第一个双冒号表示通过类名方式访问//第二个双冒号表示访问父类作用域下 cout << B::A::m_A << endl;//父类100 } //函数 void test2() { //1.通过对象来访问函数 cout << "通过对象来访问函数" << endl; A a; a.func();//父类 B b; b.func();//子类 b.A::func();//父类 //2.通过类名来访问函数 cout << "通过类名来访问函数" << endl; A::func();//父类 B::func();//子类 //第一个双冒号表示通过类名方式访问//第二个双冒号表示访问父类作用域下 B::A::func();//父类 } int main() { test1(); test2(); system("pause"); return 0; }
-
- 多继承语法
-
语法:
class 子类:继承方式 父类1,继承方式 父类2{};
-
注意:
- C++实际开发中不建议用多继承
- 多继承中父类出现同名情况时,通过子类去访问需要加作用域
-
代码:
#include<iostream> using namespace std; //多继承语法 class A1 { public: A1() { m_A = 100; } int m_A; }; class A2 { public: A2() { m_A = 200; } int m_A; }; class B :public A1, public A2 { public: B() { m_C = 300; } int m_C; }; void test() { B b; cout << sizeof(b) << endl;//12 cout << b.A1::m_A << endl;//100 cout << b.A2::m_A << endl;//200 cout << b.m_C << endl;//300 } int main() { test(); system("pause"); return 0; }
-
- 菱形继承
- 概念:
- 两个子类继承同一个父类,接着有一个新的类同时继承这两个子类,这种继承方式称为菱形继承,或者钻石继承
- 示意图:
- 使用虚继承(继承指针)可以解决会同时继承A中的两份相同数据的问题,使得数据只有一份
- 语法:
class B1:virtual 继承方式 A{};
对中间的两个子类都写关键字virtual- A叫做虚基类
- 语法:
- 概念:
-
多态(多种形态)(父类的指针或引用指向子类的对象)(一个函数有多种形态,使用不同的子类时对应同一个函数的不同具体实现)
- 多态是C++面向对象三大特性之一
-
优点
- 组织结构清晰
- 可读性强
- 对于前期和后期扩展一级维护性高
-
分类
- 静态多态:函数重载和运算符重载属于静态多态,复用函数名
- 静态多态的函数地址早绑定-编译阶段确定函数地址
- 动态多态:派生类和虚函数实现运行时多态
-
动态多态的函数地址晚绑定-运行阶段确定函数地址
-
满足条件:
- 有继承关系
- 子类要重写(函数返回值类型,函数名,形参列表都完全相同)父类的虚函数
-
使用方法:
- 父类的指针或者引用指向子类对象
-
代码:
#include<iostream> using namespace std; class Animal { public: virtual void speak()//虚函数//可以实现地址晚绑定//一开始不能确定哪个类,得传进来才能确定 { cout << "动物在说话" << endl; } }; //猫类 class Cat :public Animal { public: void speak() { cout << "小猫在说话" << endl; } }; void doSpeak(Animal &animal)//Animal &animal=Cat; { animal.speak(); } void test1() { Cat cat; doSpeak(cat);//小猫在说话//如果不用虚函数则是动物在说话 } int main() { test1(); system("pause"); return 0; }
-
实现流程:
-
- 静态多态:函数重载和运算符重载属于静态多态,复用函数名
-
多态实现计算器
-
代码:
#include<iostream> #include<string> using namespace std; //普通实现计算器 class Calculator { public: int getResult(string opr) { if (opr == "+") { return m_Num1 + m_Num2; } else if(opr=="-") { return m_Num1 - m_Num2; } else if (opr == "*") { return m_Num1 * m_Num2; } } int m_Num1; int m_Num2; }; void test1() { Calculator cal; cal.m_Num1 = 10; cal.m_Num2 = 20; cout<<cal.getResult("+")<<endl; cout<<cal.getResult("-")<<endl; cout<<cal.getResult("*")<<endl; } //利用多态实现计算器 //实现计算器抽象类 class AbstractCalculator { public: virtual int getResul() { return 0; } int m_Num1; int m_Num2; }; //加法计算器类 class AddCalculator :public AbstractCalculator { public: virtual int getResul()//这里的virtual关键字可加可不加 { return m_Num1+m_Num2; } }; //减法计算器类 class SubCalculator :public AbstractCalculator { public: virtual int getResul()//这里的virtual关键字可加可不加 { return m_Num1-m_Num2; } }; //乘法计算器类 class MulCalculator :public AbstractCalculator { public: virtual int getResul()//这里的virtual关键字可加可不加 { return m_Num1*m_Num2; } }; void test2() { //父类指针或者引用指向子类对象 //加法运算 AbstractCalculator* abc = new AddCalculator; abc->m_Num1 = 10; abc->m_Num2 = 20; cout << abc->getResul() << endl; delete abc;//因为用了new创建在堆区,所以需要手动释放 //减法运算 abc = new SubCalculator; abc->m_Num1 = 10; abc->m_Num2 = 20; cout << abc->getResul() << endl; delete abc;//因为用了new创建在堆区,所以需要手动释放 //乘法运算 abc = new MulCalculator; abc->m_Num1 = 10; abc->m_Num2 = 20; cout << abc->getResul() << endl; delete abc;//因为用了new创建在堆区,所以需要手动释放 } int main() { cout << "普通计算器实现" << endl; test1(); cout << "多态计算器实现" << endl; test2(); system("pause"); return 0; }
-
-
纯虚函数和抽象类
-
纯虚函数
- 语法:
virtual 返回值类型 函数名(形参列表)=0;
- 不需要{}内的内容了
- 作用:在多态中,通常父类中的纯虚函数的实现是毫无意义的,主要都是调用子类重写的内容
- 语法:
-
抽象类
*概念:当类中有了纯虚函数,这个类也称为抽象类- 特点:
- 无法实例化对象
类名 *指针变量
并不是实例化对象,是可以使用的
- 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
- 无法实例化对象
- 特点:
-
代码:
#include<iostream> using namespace std; //纯虚函数和抽象类 class Base { public: virtual void func() = 0;//纯虚函数,即完全没有意义的函数,不需要具体实现 }; class Son :public Base { public: }; void test1() { //Base b;//抽象类无法实例化对象 //new Base;//抽象类无法实例化对象 //Son s;//子类因为没有重写虚函数,所以也是抽象类,抽象类无法实例化对象 //new Son;//子类因为没有重写虚函数,所以也是抽象类,抽象类无法实例化对象 } int main() { system("pause"); return 0; }
-
-
虚析构和纯虚析构
-
作用:解决在多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用子类的析构代码(如果子类中没有开辟的堆区数据,可以不把父类的析构写为虚析构或纯虚析构)
-
虚析构和纯虚析构共性
- 可以解决父类指针释放子类对象
- 都需要有具体的函数实现
-
虚析构和纯虚析构区别
- 如果是纯虚析构,该类属于抽象类,无法实例化对象
-
纯虚析构和纯虚函数区别
- 纯虚析构需要类外定义,纯虚函数不需要类外定义,纯虚函数需要子类重写
-
虚析构
- 语法:
virtual ~类名(){}
- 语法:
-
纯虚析构(类内声明,类外定义)
- 语法:
virtual ~类名()=0;类名::(){具体实现}
- 语法:
-
代码:
#include<iostream> #include<string> using namespace std; //虚析构和纯虚析构 class Animal { public: Animal() { cout << "Animal构造函数调用" << endl; } 利用虚析构可以解决父类指针释放子类对象不干净的问题 //virtual ~Animal() //{ // cout << "Animal析构函数调用" << endl; //} //纯虚析构 纯虚析构需要自己声明也需要自己实现 virtual ~Animal() = 0; //纯虚函数 virtual void speak() = 0; }; //纯虚析构 Animal::~Animal() { cout << "Animal析构函数调用" << endl; } class Cat :public Animal { public: Cat(string name) { cout << "Cat构造函数调用" << endl; m_Name=new string(name);//堆区创建了,需要释放 } virtual void speak() { cout << *m_Name<<"小猫在说话" << endl; } ~Cat() { cout << "Cat析构函数调用" << endl; if (m_Name != NULL)//如果指针存储的地址不为空,说明该地址有内存空间存在 { delete m_Name; m_Name = NULL;//把指针变量存储的内容(地址)置为空 } } string* m_Name; }; void test1() { Animal *animal = new Cat("Tom");//父类指向子类对象 animal->speak(); //父类指针在delete时不会调用用子类中析构函数,导致子类如果有堆区数据会出现内存泄露 delete animal; } int main() { test1(); system("pause"); return 0; }
-
七.C++文件操作
- 文件类型:
- 文本文件:文件以文本的ASCII码形式存储在计算机中
- 二进制文件:文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们
- 操作文件的三大类
- ofstream:写操作
- o代码output,
- f代表file
- output to file(输出到文件)
- ifstream:读操作
- i代表input
- f代表file
- input from file
- fstream:读写操作
- 没有前缀字母表示读和写都行
- ofstream:写操作
- 文本文件
- 写文件(类似cout)
-
步骤
- 包含头文件:
#include<fstream>
- 创建流对象:
ofstream ofs
- 打开文件:
ofs.open("文件路径",打开方式);
- 打开方式:
- 注意:文件打开方式可以配合使用,利用|操作符
- 如用二进制方式写文件:
ios::binary | ios::out
- 如用二进制方式写文件:
- 打开方式:
- 写数据:
ofs<<写入的数据;
- 向文件写入数据
- 关闭文件:
ofs.close();
- 包含头文件:
-
代码:
#include<iostream> #include<fstream> using namespace std; //文本文件 写文件 void test1() { ofstream ofs; ofs.open("test.txt", ios::out); ofs << "Hello" << endl; ofs << "World" << endl; ofs.close(); } int main() { test1(); system("pause"); return 0; }
-
- 读文件(类似cin)
- 步骤
- 包含头文件:
#include<fstream>
- 创建流对象:
ifstream ifs
- 打开文件并判断文件是否打开成功:
ifs.open("文件路径",打开方式);
- 打开方式:
- 注意:文件打开方式可以配合使用,利用|操作符
- 如用二进制方式写文件:
ios::binary | ios::out
- 如用二进制方式写文件:
- 打开方式:
- 读数据(4种方式读取):
-
代码:
#include<iostream> #include<string> //1 #include<fstream> using namespace std; //文本文件 读文件 void test() { //2 ifstream ifs; //3 ifs.open("test.txt", ios::in); if (!ifs.is_open()) { cout << "文件打开失败" << endl; } //4 第一种 //char buf[1024] = { 0 }; //while (ifs >> buf)//读到EOF,输入流对象就会变成假,跳出循环 //{ // cout << buf << endl; //} 第二种 //char buf[1024] = { 0 }; //while (ifs.getline(buf,1024)) //{ // cout << buf << endl; //} 第三种 //string buf; //while (getline(ifs, buf)) //{ // cout << buf << endl; //} 第四种(不太推荐用) //char c; //while ((c = ifs.get()) != EOF)//如果读取字符没读到文件尾,则一直读 //{ // cout << c; //} //5 ifs.close(); } int main() { test(); system("pause"); return 0; }
-
- 关闭文件:
ifs.close();
- 包含头文件:
- 步骤
- 写文件(类似cout)
- 二进制文件
- 以二进制的方式对文件进行读写操作,打开方式要指定为
ios::binary
- 写文件(write)
-
代码:
#include<iostream> #include<fstream> using namespace std; //二进制文件 写文件 class Person { public: char m_Name[64]; int m_Age; }; void test() { ofstream ofs; ofs.open("person.txt", ios::out | ios::binary); Person p = { "张三",18 }; ofs.write((const char*)&p, sizeof(Person));//强制转化成const char * ofs.close(); } int main() { test(); system("pause"); return 0; }
-
- 读文件(read)
-
代码:
#include<iostream> #include<fstream> using namespace std; class Person { public: char m_Name[64]; int m_Age; }; //二进制文件 读文件 void test() { ifstream ifs; ifs.open("Person.txt", ios::in | ios::binary); if (!ifs.is_open()) { cout << "文件打开失败" << endl; return; } Person p; ifs.read((char*)&p, sizeof(Person));//强制转化成char * cout << p.m_Name << endl; cout << p.m_Age << endl; ifs.close(); } int main() { test(); system("pause"); return 0; }
-
- 以二进制的方式对文件进行读写操作,打开方式要指定为
八.模板
- 作用:建立通用的模具,大大提高复用性
8.1函数模板
-
作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表
-
函数模板定义语法:
template<typename T> 函数声明或定义
- 第一行不加分号
- template–声明创建模板
- typename–表明其后面的符号是一种数据类型,可以用class代替
- T–通用的数据类型,名称可以替换,通常为大写字母
-
函数模板调用语法:
-
自动类型推导
函数名(形参);
-
显示指定类型(建议使用这种方法)(就类似一种传参,只不过传的不再是变量,而是传数据类型)
函数名<形参的类型>(形参);
-
-
注意事项
- 自动类型推导,必须推导出一致的数据类型T才可以使用
- 声明了函数模板后必须让T确定自己的数据类型(有形参传形参,没形参就使用显示指定类型使T确定自己类型),否则调用函数会报错
-
普通函数和函数模板区别(能否发生隐式类型转换)
- 普通函数调用时,可以发生自动类型转换(隐式类型转换)
- 函数模板使用自动类型推导时,不会发生隐式类型转换
- 函数模板使用显示指定类型时,可以发生隐式类型转换
-
普通函数与函数模板同名时的调用规则
-
如果函数模板和普通函数都可以实现,优先调用普通函数
-
可以通过空模板参数列表来强制调用函数模板
-
函数模板也可以发生重载
-
如果函数模板可以产生更好的匹配优先调用函数模板
-
代码:
#include<iostream> using namespace std; void myPrint(int a, int b) { cout << "调用普通函数" << endl; } template<typename T> void myPrint(T a, T b,T c)//函数模板重载 { cout << "调用函数重载模板" << endl; } template<typename T> void myPrint(T a, T b) { cout << "调用函数模板" << endl; } void test1()//1.普通函数和函数模板都可以实现的话,优先调用普通函数 { int a = 10; int b = 20; myPrint(a, b); } void test2()//2.通过空模板参数列表强制调用函数模板 { int a = 10; int b = 20; myPrint<>(a, b); } void test3()//3.函数模板重载调用 { int a = 10; int b = 20; int c = 30; myPrint(a, b,c);//或者myPrint<>(a, b,c)这样也是一样的结果 } void test4()//4.如果函数模板产生更好的匹配(大概指不用隐式类型转换),优先调用函数模板 { char c1 = 'a'; char c2 = 'b'; myPrint(c1, c2); } int main() { test1();//普通函数 test2();//函数模板 test3();//函数重载模板 test4();//函数模板 system("pause"); return 0; }
-
-
模板的局限性
-
模板的通用性不是万能的,自定义数据类型无法实现
-
用具体化模板解决自定义类型的通用化
- 语法:
template<> 函数模板的定义
- 之前的通用化函数模板还保留,只是多加这一个具体化函数模板
- 语法:
-
代码:
#include<iostream> #include<string > using namespace std; class Person { public: Person(string name, int age) { m_Name = name; m_Age = age; } string m_Name; int m_Age; }; template<typename T> bool myCompare(T &a, T &b) { if (a == b) { return true; } else { return false; } } //利用具体化的Person的版本实现代码,具体化优先调用 template<> bool myCompare(Person& p1, Person& p2) { if (p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age) { return true; } else { return false; } } void test1() { int a = 10; int b = 10; cout << myCompare(a, b) << endl; } void test2() { Person p1("Tom",10); Person p2("Tom",10); cout<<myCompare(p1, p2)<<endl; } int main() { test1();//1 test2();//1//具体化函数模板 system("pause"); return 0; }
-
8.2类模板
-
作用:建立一个通用类,类中的成员数据类型可以先不确定,用一个虚拟的类型来代替
-
语法:
- 不带默认参数
template<class T> 类
- 带默认参数
template<class T=int> 类
- 第一行不加分号
- template–声明创建模板
- class–表明其后面的符号是一种数据类型,可以用typename代替
- T–通用的数据类型,名称可以替换,通常为大写字母
- 不带默认参数
-
类模板调用语法:
-
显示指定类型(只有这种调用语法,没有自动类型推导)
类名<类中成员的形参列表类型> 变量名;
-
-
类模板中成员函数创建时机
- 类模板中成员函数和普通类中成员函数创建时机
- 普通类中的成员函数一开始就可以创建
- 类模板中的成员函数在被调用时才创建
- 类模板中成员函数和普通类中成员函数创建时机
-
类模板对象做函数参数
-
传入方式
- 指定传入的类型 – 直接显示对象的数据类型(最常用)
- 参数模板化 – 将对象中的参数变为模板进行传递
- 整个类模板化 – 将这个对象类型模板化进行传递
-
代码
#include<iostream> #include<string> using namespace std; //类模板对象做函数参数 template<class T1,class T2> class Person { public: Person(T1 name, T2 age) { m_Name = name; m_Age = age; } void showPerson() { cout << m_Name << " " << m_Age << endl; } T1 m_Name; T2 m_Age; }; //1.指定传入类型 void printPerson1(Person<string, int> &p) { p.showPerson(); } void test1() { Person<string, int> p("张三", 10); printPerson1(p); } //2.参数模板化 template<class T1, class T2> void printPerson2(Person<T1, T2>& p) { p.showPerson(); //看模板推出的数据类型是什么 cout << "T1的类型为:" << typeid(T1).name() << endl; cout << "T2的类型为:" << typeid(T2).name() << endl; } void test2() { Person<string, int> p("李四", 20); printPerson2(p); } //3.类模板化 template<class T> void printPerson3(T &p) { p.showPerson(); //看模板推出的数据类型是什么 cout << "T1的类型为:" << typeid(T).name() << endl; } void test3() { Person<string, int> p("王五", 30); printPerson3(p); } int main() { test1(); test2(); test3(); system("pause"); return 0; }
-
-
类模板与继承
-
当子类继承的父类是一个类模板时,子类在声明的时候要指定出父类中T的类型
-
如果不指定,编译器无法给子类分配内存
-
如果想灵活指定出父类中T的类型,子类也需变为类模板
-
代码:
#include<iostream> using namespace std; //类模板与继承 template<class T> class Base { T m; }; //class Son:public Base//必须要知道父类中的T具体类型才能继承给子类 class Son1 :public Base<int> { }; void test1() { Son1 s; } //如果想灵活指定父类中T类型,子类也需要变成类模板 template<class T1,class T2> class Son2 :public Base<T2>//T2是父类中的成员类型 { public: Son2() { cout << typeid(T1).name() << endl;//int cout << typeid(T2).name() << endl;//char } T1 obj;//T1是子类中的成员类型 }; void test2() { Son2<int, char> s2; } int main() { test1(); test2(); system("pause"); return 0; }
-
-
类模板成员函数类外实现
-
语法:
类模板声明 成员函数返回类型 类名<类模板形参列表>::成员函数名(){}//相对于类的成员函数类外实现需要加类模板声明以及类模板形参列表,都是必加的,即使成员函数没用到形参列表也要加类模板形参列表
-
代码:
#include<iostream> using namespace std; //类模板成员函数类外实现 template<class T1,class T2> class Person { public: Person(T1 name, T2 age); void showPerson(); T1 m_Name; T2 m_Age; }; //构造函数类外实现 template<class T1, class T2> Person<T1,T2>::Person(T1 name, T2 age) { m_Name = name; m_Age = age; } //成员函数类外实现 template<class T1, class T2> void Person<T1,T2>::showPerson() { cout << m_Name << endl; cout << m_Age << endl; } void test1() { Person<string,int> p1("张三",10); p1.showPerson(); } int main() { test1(); system("pause"); return 0; }
-
-
类模板分文件编写
- 问题:类模板中成员函数创建时机是在成员函数被调用阶段,导致分文件编写时链接不到
- 解决方法:
- 直接包含.cpp源文件
- 将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp(.h头文件+.cpp源文件)是约定的名称,不是一定要这个名字(常用)
-
类模板与友元
-
全局函数类内实现-直接在类内声明友元即可(建议用这个)
-
全局函数类外实现-需要提前让编译器知道全局函数的存在(黑马P181,好复杂)
-
代码:
#include<iostream> #include<string> using namespace std; //通过全局函数 打印Person信息 //2.全局函数类外实现 //提前让编译器知道Person类的存在 template<class T1, class T2> class Person; //提前让编译器知道全局函数的存在 template<class T1, class T2> void printPerson2(Person<T1, T2> p)//参数模板化 { cout << p.m_Name << endl; cout << p.m_Age << endl; } template<class T1, class T2> class Person { //全局函数 类内实现 friend void printPerson1(Person<T1, T2> p)//参数模板化 { cout << p.m_Name << endl; cout << p.m_Age << endl; } //全局函数 类外实现 //需要加类模板的空参数列表 //提前让编译器知道这个普通函数的存在 friend void printPerson2<>(Person<T1, T2> p);//参数模板化 public: Person(T1 name, T2 age) { m_Name = name; m_Age = age; } private: T1 m_Name; T2 m_Age; }; //1.全局函数类内实现 void test1() { Person<string, int> p("张三", 10); printPerson1(p); } void test2() { Person<string, int> p("李四", 20); printPerson2(p); } int main() { test1(); test2(); system("pause"); return 0; }
-
-
类模板案例
- 功能
- 代码:待更新
九.STL(Standard Template Library标准模板库)
- 概念:分为容器(container),算法(algorithm),迭代器(ierator)
- STL六大组件
- 容器:各种数据结构,如vetor、list、deque、set、map等,用来存放数据
- 算法:各种常用的算法,如sort、find、copy、for_each等
- 迭代器:容器与算法之间的桥梁
- 仿函数:行为类似函数,可以作为算法的某种策略
- 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
- 空间配置器(配接器):负责空间的配置与管理
- STL中容器、算法、迭代器
- STL容器:将运用最广泛的一些数据结构实现出来
- 序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置
- 关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系
- 算法:
- 质变算法:运算过程中会更改去间内的元素的内容,例如拷贝,替换,删除等等
- 非质变算法:是指运算过程中不会更改去间的元素内容,例如查找、计数、遍历、寻找极值等等
- 迭代器(类似指针):提供一种方法,使之能够依序寻访某个容器中所含的各个元素,而又无需暴露该容器的内部表示方式。每个容器都有自己专属的迭代器。算法要通过迭代器才能访问容器里的元素
- 种类:(常用双向迭代器和随机访问迭代器)
- 种类:(常用双向迭代器和随机访问迭代器)
- STL容器:将运用最广泛的一些数据结构实现出来
4.容器
- vector容器
-
小技巧:尖括号内是什么类型,解引用出来后就是什么类型
-
代码:
#include<iostream> #include<string> #include<vector> using namespace std; //vector容器中存放自定义数据类型 class Person { public: Person(string name, int age) { m_Name = name; m_Age = age; } string m_Name; int m_Age; }; //存放类 void test1() { vector<Person> v; Person p1("a", 10); Person p2("b", 20); Person p3("c", 30); Person p4("d", 40); Person p5("e", 50); //向容器中添加数据 v.push_back(p1); v.push_back(p2); v.push_back(p3); v.push_back(p4); v.push_back(p5); //遍历容器中的数据 for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) { cout << "姓名:" << (*it).m_Name << endl; cout << "年龄:" << (*it).m_Age << endl; } } //2.存放自定义数据类型 指针 void test2() { vector<Person*> v; Person p1("a", 10); Person p2("b", 20); Person p3("c", 30); Person p4("d", 40); Person p5("e", 50); //向容器中添加数据 v.push_back(&p1); v.push_back(&p2); v.push_back(&p3); v.push_back(&p4); v.push_back(&p5); //遍历容器中的数据 for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++) { cout << "姓名:" << (*it)->m_Name << endl; cout << "年龄:" << (*it)->m_Age << endl; } } int main() { test2(); system("pause"); return 0; }
-
嵌套代码:
#include<iostream> #include<vector> using namespace std; void test() { vector<vector<int>> v; vector<int> v1; vector<int> v2; vector<int> v3; v1.push_back(1); v1.push_back(2); v1.push_back(3); v2.push_back(4); v2.push_back(5); v2.push_back(6); v3.push_back(7); v3.push_back(8); v3.push_back(9); v.push_back(v1); v.push_back(v2); v.push_back(v3); for (vector<vector<int>> ::iterator it = v.begin(); it != v.end(); it++) { for (vector<int> ::iterator vit = (*it).begin(); vit != (*it).end(); vit++) { cout << *vit << " "; } cout << endl; } } int main() { test(); system("pause"); return 0; }
-
4.1string容器
- string的构造函数
string(); //创建一个空的字符串,如string str
string(const char *s); //使用字符串s初始化
string(const string& str); //使用一个string对象初始化另一个string对象
string(int n,char c); //使用n个字符c初始化
- 代码:
#include<iostream> #include<string> using namespace std; void test1() { string s1;//默认构造 const char* str = "hello world"; string s2(str); cout <<"s2:" << s2 << endl; string s3(s2); cout << "s3:" << s3 << endl; string s4(10, 'a'); cout << "s4:" << s4 << endl; } int main() { test1(); system("pause"); return 0; }
- string的赋值操作
- 作用:给string字符串进行赋值
- 赋值的函数原型:
string& operator=(const char* s); //把char *类型字符串赋值给当前的string类型字符串 string& operator=(const string &s);//把string类型字符串赋值给当前的string类型字符串 string& operator=(char c); //把char类型字符赋值给当前的string类型字符串 string& assign(const char *s); //把char*类型字符串赋值给当前的string类型字符串 string& assign(const char *s,int n);//把char*类型字符串的前n个字符赋给当前的string类型字符串 string& assign(const string &s); //把string类型字符串赋值给当前string类型字符串 string& assign(int n,char c); //把n个char类型字符赋值给当前string类型字符串
- 代码:
#include<iostream> #include<string> using namespace std; /* string& operator=(const char* s); //把char *类型字符串赋值给当前的string类型字符串 string& operator=(const string &s);//把string类型字符串赋值给当前的string类型字符串 string& operator=(char c); //把char类型字符赋值给当前的string类型字符串 string& assign(const char *s); //把char*类型字符串赋值给当前的string类型字符串 string& assign(const char *s,int n);//把char*类型字符串的前n个字符赋给当前的string类型字符串 string& assign(const string &s); //把string类型字符串赋值给当前string类型字符串 string& assign(int n,char c); //把n个char类型字符赋值给当前string类型字符串 */ void test1() { string str1; str1 = "hello world"; cout << "str1=" << str1 << endl;//hello world string str2; str2 = str1; cout << "str2=" << str2 << endl;//hello world string str3; str3 = 'a'; cout << "str3=" << str3 << endl;//a string str4; str4.assign("hello C++"); cout << "str4=" << str4 << endl;//hello C++ string str5; str5.assign("hello C++",5); cout << "str5=" << str5 << endl; //hello string str6; str6.assign(str5); cout << "str6=" << str6 << endl;//hello string str7; str7.assign(10, 'w'); cout << "str7=" << str7 << endl;//wwwwwwwwww } int main() { test1(); system("pause"); return 0; }
- string字符串拼接
- 作用:实现在字符串末尾拼接字符串
- 函数原型:
string& operator+=(const char* str); //把char*类型字符串连接到当前string类型字符串结尾 string& operator+=(const char c); //把char类型字符连接到当前sring类型字符串结尾 string& operator+=(const string& str); //把string类型字符串连接到当前string类型字符串结尾 string& append(const char *s); //把char*类型字符串连接到当前string类型字符串结尾 string& append(const char *s,int n); //把char*类型字符串的前n个字符连接到当前sring类型字符串结尾 string& append(const string &s); //把string类型字符串连接到当前string类型字符串结尾 string& append(const string &s,int pos,int n); //把string类型字符串的pos下标位置开始的共n个字符连接到当前string类型字符串结尾
- 代码:
#include<iostream> #include<string> using namespace std; /* string& operator+=(const char* str); //把char*类型字符串连接到当前string类型字符串结尾 string& operator+=(const char c); //把char类型字符连接到当前sring类型字符串结尾 string& operator+=(const string& str); //把string类型字符串连接到当前string类型字符串结尾 string& append(const char *s); //把char*类型字符串连接到当前string类型字符串结尾 string& append(const char *s,int n); //把char*类型字符串的前n个字符连接到当前sring类型字符串结尾 string& append(const string &s); //把string类型字符串连接到当前string类型字符串结尾 string& append(const string &s,int pos,int n); //把string类型字符串的pos下标位置开始的共n个字符连接到当前string类型字符串结尾 */ void test1() { string str1 = "hello"; str1 += " world"; cout << "str1=" << str1 << endl;//hello world string str2 = "hell"; str2 += 'o'; cout << "str2=" << str2 << endl;//hello string str3 = "!!!"; str3 += str1; cout << "str3=" << str3 << endl;//!!!hello world string str4 = "hello "; str4.append("C++"); cout << "str4=" << str4 << endl;//hello C++ string str5 = "hello "; str5.append("C++!!!", 3); cout << "str5=" << str5 << endl;//hello C++ string str6 = "!!!"; str6.append(str4); cout << "str6=" << str6 << endl;//!!!hello C++ string str7 = "hello "; str7.append(str4, 6, 3); cout << "str7=" << str7 << endl;//hello C++ } int main() { test1(); system("pause"); return 0; }
- string查找和替换
- 功能:
- 查找:查找指定字符串是否存在
- 替换:在指定的位置替换字符串
- 函数原型
- find
- 从左往右查找
- rfind
- 从右往左查找
- replace
- 指定从哪个位置起,多少个字符,替换成什么样的字符串
- find
- 代码:
#include<iostream> #include<string> using namespace std; //函数原型 //1.查找 void test1() { string str1 = "abcdefgbc"; int pos1; pos1=str1.find("bc");//从左往右查 cout << pos1 << endl;//1 int pos2; pos2 = str1.rfind("bc");//从右往左查 cout << pos2 << endl;//7 } //2.替换 void test2() { string str1 = "abcdefg"; str1.replace(1, 3, "1111"); cout << str1 << endl;//a1111efg } int main() { test1(); test2(); system("pause"); return 0; }
- 功能:
- string字符串比较
- 功能:
- 字符串之间的比较
- 比较方式:
- 字符串比较是按字符的ASCII码进行对比
- 等于=返回 0
- 大于>返回 1
- 小于<返回 -1
- 字符串比较是按字符的ASCII码进行对比
- 函数原型:
int compare(const char *s) const;//与char *类型字符串比较 int compare(const string &s) const;//与string类型字符串比较
- 代码:
#include<iostream> #include<string> using namespace std; /* int compare(const char *s) const;//与char *类型字符串比较 int compare(const string &s) const;//与string类型字符串比较 */ void test1() { string str11 = "hello"; string str12 = "hello"; cout << str11.compare(str12) << endl;//0 string str21 = "xello"; string str22 = "hello"; cout << str21.compare(str22) << endl;//1 string str31 = "aello"; string str32 = "hello"; cout << str31.compare(str32) << endl;//-1 } int main() { test1(); system("pause"); return 0; }
- 功能:
- string 字符存取
- 功能:存取字符
- 函数原型
char &operator[](int n);通过[]方式存取字符 char &at(int n);通过at方法获存取字符
- 代码
#include<iostream> #include<string> using namespace std; /* char &operator[](int n);通过[]方式存取字符 char &at(int n);通过at方法获存取字符 */ void test1() { string str = "hello"; //1.通过[]访问单个字符 for (int i = 0; i < str.size(); i++) { cout << str[i] << " ";//h e l l o } cout << endl; // //2.通过at方式访问单字符 for (int i = 0; i < str.size(); i++) { cout << str.at(i) << " ";//h e l l o } cout << endl; //3.通过[]修改单个字符 str[0] = 'H'; cout << "str=" << str << endl;//Hello //4.通过at修改单个字符 str.at(1) = 'E'; cout << "str=" << str << endl;//HEllo } int main() { test1(); system("pause"); return 0; }
- string字符串插入和删除
- 功能:对string字符串进行插入和删除操作
- 函数原型
string &insert(int pos,const char* s); //在pos下标位置插入char*类型字符串 string &insert(int pos,const string &str); //在pos下标位置插入string 类型字符串 string insert(int pos,int n,char c); //在指定位置插入n个字符c string &erase(int pos,int n=npos); //删除从pos下标开始的n个字符
- 代码
#include<iostream> #include<string> using namespace std; /* string &insert(int pos,const char* s); //在pos下标位置插入char*类型字符串 string &insert(int pos,const string &str); //在pos下标位置插入string 类型字符串 string insert(int pos,int n,char c); //在指定位置插入n个字符c string &erase(int pos,int n=npos); //删除从pos下标开始的n个字符 */ void test1() { string str = "hllo"; //1.插入 str.insert(1, "e"); cout << "str=" << str << endl;//hello //2.删除 str.erase(1, 3); cout << "str=" << str << endl;//ho } int main() { test1(); system("pause"); return 0; }
- string截取子串
- 功能:从字符串中获取想要的子串
- 函数原型
string substr(int pos=0,int n=npos) const;//返回由pos开始的n个字符组成的string类型字符串
- 代码
#include<iostream> #include<string> using namespace std; /* string substr(int pos=0,int n=npos) const;//返回由pos开始的n个字符组成的string类型字符串 */ void test1() { string str = "abcdef"; string subStr = str.substr(1, 3); cout << "subStr=" << subStr << endl; } int main() { test1(); system("pause"); return 0; }
4.2 vector容器(类似数组)
4.2.1 vector构造函数
-
功能:创建vector容器
-
函数原型
vector<T> v; //采用模板实现,默认构造函数 vector(v.begin(),v.end()); //将v[begin(),end())左闭右开区间中的元素拷贝给本身 vector(n,elem); //构造函数将n个elem拷贝给本身 vector(const vector &vec) //拷贝构造函数
-
代码
#include<iostream> #include<vector> using namespace std; /* vector<T> v; //采用模板实现,默认构造函数 vector(v.begin(),v.end()); //将v[begin(),end())左闭右开区间中的元素拷贝给本身 vector(n,elem); //构造函数将n个elem拷贝给本身 vector(const vector &vec) //拷贝构造函数 */ //打印vector内容 void printVector(vector<int> &v) { for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { //1.默认构造 无参构造 vector<int> v1; for (int i = 0; i < 10; i++) { v1.push_back(i); } printVector(v1);//0 1 2 3 4 5 6 7 8 9 //2.通过区间方式进行构造 vector<int> v2(v1.begin(), v1.end()); printVector(v2);//0 1 2 3 4 5 6 7 8 9 //3.通过n个element方式进行构造 vector<int> v3(10, 100); printVector(v3);//100 100 100 100 100 100 100 100 100 100 //4.拷贝构造 vector<int> v4(v3); printVector(v4);//100 100 100 100 100 100 100 100 100 100 } int main() { test1(); system("pause"); return 0; }
4.2.2 vector赋值操作
-
功能:给vector容器进行赋值
-
函数原型
/* vector &operator=(const vector &vec);//重载等号操作符 assign(beg,end); //将[beg,end)区间钟的数据拷贝赋值给本身 assign(n,elem); //将n个elem拷贝赋值给本身 */
-
代码
#include<iostream> #include<vector> using namespace std; /* vector &operator=(const vector &vec);//重载等号操作符 assign(beg,end); //将[beg,end)区间钟的数据拷贝赋值给本身 assign(n,elem); //将n个elem拷贝赋值给本身 */ void printVector(vector<int> &v) { for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { vector<int> v1; for (int i = 0; i < 10; i++) { v1.push_back(i); } printVector(v1);//0 1 2 3 4 5 6 7 8 9 //1.重载赋值 vector<int> v2; v2 = v1; printVector(v2);//0 1 2 3 4 5 6 7 8 9 //2.assign赋值另一个v vector<int> v3; v3.assign(v1.begin(), v1.end()); printVector(v3);//0 1 2 3 4 5 6 7 8 9 //3.assingn赋值n个元素 vector<int> v4; v4.assign(10, 100); printVector(v4);//100 100 100 100 100 100 100 100 100 100 } int main() { test1(); system("pause"); return 0; }
4.2.3 vector容量和大小
-
功能:读取与改变vector容器的容量和大小
-
函数原型
empty(); //判断容器是否为空 capacity(); //返回容器的容量(容器容量始终大于或等于容器中元素个数) size() //返回容器中元素的个数 resize(int num) //重新指定容器中元素的个数为num,若容器变长,则以默认值0填充新增长的位置;如果容器变短,则末尾超出元素个数的部分被删除 resize(int num,elem) //重新指定容器中元素的个数为num,若容器变长,则以elem填充新增长的位置;如果容器变短,则末尾超出元素个数的部分被删除
-
代码
#include<iostream> #include<vector> using namespace std; /* empty(); //判断容器是否为空 capacity(); //返回容器的容量(容器容量始终大于或等于容器中元素个数) size() //返回容器中元素的个数 resize(int num) //重新指定容器中元素的个数为num,若容器变长,则以默认值0填充新增长的位置;如果容器变短,则末尾超出元素个数的部分被删除 resize(int num,elem) //重新指定容器中元素的个数为num,若容器变长,则以elem填充新增长的位置;如果容器变短,则末尾超出元素个数的部分被删除 */ void printVector(vector<int>& v) { for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { vector<int> v1; for (int i = 0; i < 10; i++) { v1.push_back(i); } printVector(v1);// //1.判断是否为空 cout << v1.empty() << endl;//0 说明v1不为空 //2.计算vector容量 cout << v1.capacity() << endl;//13 //3.计算vector大小 cout << v1.size() << endl;//10 //4.重新指定vector大小,默认填充值为0 v1.resize(15); cout << v1.size() << endl;//15 cout << v1.capacity() << endl;//19 printVector(v1);//0 1 2 3 4 5 6 7 8 9 0 0 0 0 0 v1.resize(3); cout << v1.size() << endl;//3 cout << v1.capacity() << endl;//19 printVector(v1);//0 1 2 //5.重新指定vector大小,并设置默认填充值 v1.resize(6,-1); cout << v1.size() << endl;//6 cout << v1.capacity() << endl;//19 printVector(v1);//0 1 2 -1 -1 -1 } int main() { test1(); system("pause"); return 0; }
4.2.4 vector插入和删除
-
功能:对vector容器进行插入、删除操作
-
函数原型
push_back(element); //在vector尾部擦汗如元素element pop_back(); //删除vector最后一个元素 insert(const_iterator pos,int count,element); //在迭代器指向位置pos插入元素element insert(const_iterator pos,int count,element); //在迭代器指向位置pos插入count个元素element erase(const_iterator pos); //删除迭代器指向位置pos处的元素 erase(const_iterator start,const_iterator end); //删除迭代器指向区间[start,end)左闭右开内的所有元素 clear(); //删除vector容器中的所有元素
-
代码
#include<iostream> #include<vector> using namespace std; /* push_back(element); //在vector尾部擦汗如元素element pop_back(); //删除vector最后一个元素 insert(const_iterator pos,int count,element); //在迭代器指向位置pos插入元素element insert(const_iterator pos,int count,element); //在迭代器指向位置pos插入count个元素element erase(const_iterator pos); //删除迭代器指向位置pos处的元素 erase(const_iterator start,const_iterator end); //删除迭代器指向区间[start,end)左闭右开内的所有元素 clear(); //删除vector容器中的所有元素 */ void printVector(vector<int>& v) { for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { vector<int> v1; //1.尾插 for (int i = 0; i < 5; i++) { v1.push_back(i); } printVector(v1);//0 1 2 3 //2.尾删 v1.pop_back(); printVector(v1);//0 1 2 3 4 //3.在迭代器位置插入 v1.insert(v1.begin(), -1); printVector(v1);//-1 0 1 2 3 //4.在迭代器位置插入多个元素 v1.insert(v1.begin(),2, -1); printVector(v1);//-1 -1 -1 0 1 2 3 //5.删除指定迭代器位置元素 v1.erase(v1.begin()); printVector(v1);//-1 -1 0 1 2 3 //6.删除指定迭代器区间元素 v1.erase(v1.begin(),v1.end()); printVector(v1);// cout << v1.empty() << endl;//1 //7.清空 v1.clear(); printVector(v1);// cout << v1.empty() << endl;//1 } int main() { test1(); system("pause"); return 0; }
4.2.5 vector数据存取
-
功能:对vector中的数据的存取操作
-
函数原型
/* at(int idx); //返回索引idx所指的元素 operator[]; //返回索引所指的元素 front(); //返回vector容器中第一个元素 back(); //返回vector容器中最后一个元素 */
-
代码
#include<iostream> #include<vector> using namespace std; /* at(int idx); //返回索引idx所指的元素 operator[]; //返回索引所指的元素 front(); //返回vector容器中第一个元素 back(); //返回vector容器中最后一个元素 */ void test1() { vector<int> v1; for (int i = 0; i < 10; i++) { v1.push_back(i); } //1.通过中括号取元素 for (int i = 0; i < v1.size(); i++) { cout << v1[i] << " ";//0 1 2 3 4 5 6 7 8 9 } cout << endl; //2.通过at方式取元素 for (int i = 0; i < v1.size(); i++) { cout << v1.at(i) << " ";//0 1 2 3 4 5 6 7 8 9 } cout << endl; //3.取vector中的第一个元素 cout << v1.front() << endl;//0 //4.取vector中的最后一个元素 cout << v1.back() << endl;//9 } int main() { test1(); system("pause"); return 0; }
4.2.6vector互换容器
-
功能:实现两个容器内的元素互换
-
函数原型
swap(vec); //将vec与本身的元素互换
-
代码
#include<iostream> #include<vector> using namespace std; /* swap(vec); //将vec与本身的元素互换 */ void printVector(vector<int>& v) { for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } //1.基本使用 void test1() { vector<int> v1; for (int i = 0; i < 10; i++) { v1.push_back(i); } vector<int> v2; for (int i = 9; i >= 0; i--) { v2.push_back(i); } printVector(v1); //0 1 2 3 4 5 6 7 8 9 printVector(v2);//9 8 7 6 5 4 3 2 1 0 v1.swap(v2); printVector(v1); //9 8 7 6 5 4 3 2 1 0 printVector(v2);//0 1 2 3 4 5 6 7 8 9 } //2.实际用途(巧用swap可以收缩内存空间) void test2() { vector<int> v; for (int i = 0; i < 100000; i++) { v.push_back(i); } cout << v.capacity() << endl;//138255 cout << v.size() << endl;//100000 v.resize(3); cout << v.capacity() << endl;//138255 cout << v.size() << endl;//3 //巧用swap收缩内存(创建匿名对象) vector<int>(v).swap(v); cout << v.capacity() << endl;//3 cout << v.size() << endl;//3 } int main() { test1(); test2(); system("pause"); return 0; }
4.2.7 vector预留空间
-
功能:减少vector在动态扩展容量时的扩展次数
-
函数原型
reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问(即和resize不同,没有默认元素,所以一开始不能访问,得赋值后才可以访问)
-
代码
#include<iostream> #include<vector> using namespace std; /* reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问(即和resize不同,没有默认元素,所以一开始不能访问,得赋值后才可以访问) */ //不利预留空间 void test1() { vector<int> v1; int num1 = 0;//统计开辟内存次数 //并不会在原有内存上往后连续开辟,而是释放掉此处的内存空间,重新找新空间开辟,因为不确定往后连续开辟的内存空间是否已经被使用了 int* p = NULL; for (int i = 0; i < 100000; i++) { v1.push_back(i); if (p != &v1[0]) { p = &v1[0]; num1++; } } cout << num1 << endl;//30 } //利用reserve预留空间 void test2() { vector<int> v1; //利用reserve预留空间 v1.reserve(100000); int num2 = 0;//统计开辟内存次数 //并不会在原有内存上往后连续开辟,而是释放掉此处的内存空间,重新找新空间开辟,因为不确定往后连续开辟的内存空间是否已经被使用了 int* p = NULL; for (int i = 0; i < 100000; i++) { v1.push_back(i); if (p != &v1[0]) { p = &v1[0]; num2++; } } cout << num2 << endl;//1 } int main() { test1();//30 test2();//1 system("pause"); return 0; }
4.2.8 vector排序
-
功能:利用算法实现对vector容器进行排序
-
函数原型
算法 sort(iterator beg,iterator end);//对[beg,end)左闭右开迭代器区间内的元素进行排序 默认升序
-
代码
#include<iostream> #include<vector> #include<algorithm>//标准算法头文件 using namespace std; /* 算法 sort(iterator beg,iterator end);//对[beg,end)左闭右开迭代器区间内的元素进行排序 默认升序 */ void printVector(const vector<int>& v) { for (vector<int>::const_iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { vector<int> v; v.push_back(2); v.push_back(1); v.push_back(3); printVector(v);//2 1 3 //1.vector排序 默认升序 //对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序 比如vector和deque sort(v.begin(), v.end()); printVector(v);//1 2 3 } int main() { test1(); system("pause"); return 0; }
4.3 deque容器
4.3.1 deque构造函数
-
功能:deque容器构造
-
函数原型
deque<T> d; //默认构造函数 deque(beg,end); //使用默认构造重载将迭代器[beg,end)左闭右开中对应的deque中的元素拷贝 deque(n,element); //使用默认构造重载将n个element拷贝 deque(const deque &deq); //拷贝构造函数
-
代码
#include<iostream> #include<deque> using namespace std; /* deque<T> d; //默认构造函数 deque(beg,end); //使用默认构造重载将迭代器[beg,end)左闭右开中对应的deque中的元素拷贝 deque(n,element); //使用默认构造重载将n个element拷贝 deque(const deque &deq); //拷贝构造函数 */ void printDeque(const deque<int> &d)//加const设置打印操作只能只读,迭代器同时也要修改为const_iterator { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { //1.默认构造 deque<int> d1; for (int i = 0; i < 10; i++) { d1.push_back(i); } printDeque(d1);//0 1 2 3 4 5 6 7 8 9 //2.区间 deque<int> d2(d1.begin(), d1.end());//将d1全部内容赋值初始化d2的默认构造重载 printDeque(d2);//0 1 2 3 4 5 6 7 8 9 //3.n个元素 deque<int> d3(10,100); printDeque(d3);//100 100 100 100 100 100 100 100 100 100 //4.拷贝构造 deque<int> d4(d3); printDeque(d4);//100 100 100 100 100 100 100 100 100 100 } int main() { test1(); system("pause"); return 0; }
4.3.2 deque赋值操作
-
功能:给deque容器进行赋值
-
函数原型
deque &operator=(const deque &deq); //重载等号操作符 assign(beg,end); //将迭代器[beg,end)区间中的对应的deque数据拷贝赋值给本身 assign(n,element); //将n个element元素拷贝赋值给本身
-
代码
#include<iostream> #include<deque> using namespace std; /* deque &operator=(const deque &deq); //重载等号操作符 assign(beg,end); //将迭代器[beg,end)区间中的对应的deque数据拷贝赋值给本身 assign(n,element); //将n个element元素拷贝赋值给本身 */ void printDeque(const deque<int> d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { deque<int> d1; for (int i = 0; i < 10; i++) { d1.push_back(i); } printDeque(d1);//0 1 2 3 4 5 6 7 8 9 //1.等号赋值 deque<int> d2; d2 = d1; printDeque(d2);//0 1 2 3 4 5 6 7 8 9 //2.assign区间迭代器赋值 deque<int> d3; d3.assign(d1.begin(), d1.end()); printDeque(d3);//0 1 2 3 4 5 6 7 8 9 //3.assign赋值n个element元素 deque<int> d4; d4.assign(10, 100); printDeque(d4); //100 100 100 100 100 100 100 100 100 100 } int main() { test1(); system("pause"); return 0; }
4.3.3 deque大小操作(无容量限制,所以没有capacity方法)
-
功能:对deque容器的大小进行操作
-
函数原型
deque.empty(); //判断deque是否为空 deque.size(); //返回deque中元素的个数 deque.resize(num); //重新指定deque的长度为num,若deque变长,则以默认值0填充新位置//如果deque变短,则末尾超出deque长度的元素被删除 deque.resize(num,element) //重新指定deque的长度为num,若deque变长,则设置默认值为element并填充新位置//如果deque变短,则末尾超出deque长度的元素被删除
-
代码
#include<iostream> #include<deque> using namespace std; /* deque.empty(); //判断deque是否为空 deque.size(); //返回deque中元素的个数 deque.resize(num); //重新指定deque的长度为num,若deque变长,则以默认值0填充新位置//如果deque变短,则末尾超出deque长度的元素被删除 deque.resize(num,element) //重新指定deque的长度为num,若deque变长,则设置默认值为element并填充新位置//如果deque变短,则末尾超出deque长度的元素被删除 */ void printDeque(const deque<int> &d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { deque<int> d1; for (int i = 0; i < 10; i++) { d1.push_back(i); } printDeque(d1);//0 1 2 3 4 5 6 7 8 9 //1.判断是否为空 cout << d1.empty() << endl;//0 //2.计算元素个数 cout << d1.size() << endl;//10 //3.重新指定deque长度,填充默认值为0 d1.resize(15); printDeque(d1); //0 1 2 3 4 5 6 7 8 9 0 0 0 0 0 //4.重新指定deque长度,设置填充默认值为1 d1.resize(20, -1); printDeque(d1); //0 1 2 3 4 5 6 7 8 9 0 0 0 0 0 - 1 - 1 - 1 - 1 - 1 d1.resize(6, -1); printDeque(d1); //0 1 2 3 4 5 } int main() { test1(); system("pause"); return 0; }
4.3.4 deque插入和删除
-
功能:向deque容器中插入和删除数据
-
函数原型
- 两端操作
push_back(element); //在deque尾部添加一个元素 push_front(elem); //在deque头部插入一个元素 pop_back(); //删除deque最后一个元素 pop_front(); //删除deque第一个元素
- 指定位置操作(insert和erase一定要提供迭代器型的pos数据,而不是提供int型的pos数据)
insert(pos,element); //在pos(迭代器)位置插入一个element元素的拷贝,返回新数据的位置 insert(pos,n,element); //在pos(迭代器)位置插入n个element元素,无返回值 insert(pos,beg,end); //在pos(迭代器)位置插入迭代器区间[beg,end)左闭右开对应的元素,无返回值 erase(pos); //删除pos(迭代器)位置的元素,返回下一个元素的位置 erase(beg,end); //删除迭代器[beg,end)左闭右开区间的元素,返回下一个元素的位置 clear(); //清空deque中的所有元素
- 两端操作
-
代码
#include<iostream> #include<deque> using namespace std; /* 1.两端操作 push_back(element); //在deque尾部添加一个元素 push_front(elem); //在deque头部插入一个元素 pop_back(); //删除deque最后一个元素 pop_front(); //删除deque第一个元素 2.指定位置操作 insert(pos,element); //在pos(迭代器)位置插入一个element元素的拷贝,返回新数据的位置 insert(pos,n,element); //在pos(迭代器)位置插入n个element元素,无返回值 insert(pos,beg,end); //在pos(迭代器)位置插入迭代器区间[beg,end)左闭右开对应的元素,无返回值 erase(pos); //删除pos(迭代器)位置的元素,返回下一个元素的位置 erase(beg,end); //删除迭代器[beg,end)左闭右开区间的元素,返回下一个元素的位置 clear(); //清空deque中的所有元素 */ void printDeque(const deque<int>& d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout << *it << " "; } cout << endl; } //1.两端操作 void test1() { deque<int> d1; //1.尾插 d1.push_back(10); d1.push_back(20); printDeque(d1);//10 20 //2.头插 d1.push_front(-10); d1.push_front(-20); printDeque(d1);//-20 -10 10 20 //3.尾删 d1.pop_back(); printDeque(d1);//-20 -10 10 //4.头删 d1.pop_front(); printDeque(d1);//-10 10 } //2.指定位置操作 void test2() { deque<int> d1; d1.push_back(10); d1.push_back(20); d1.push_front(-10); d1.push_front(-20); printDeque(d1);//-20 -10 10 20 //1.使用迭代器insert一个元素 d1.insert(d1.begin(), 0); printDeque(d1);//0 -20 -10 10 20 //2.使用迭代器insert多个元素 d1.insert(d1.begin(), 2, 0); printDeque(d1);//0 0 0 -20 -10 10 20 //3.使用区间迭代器插入 deque<int> d2; d2.push_back(1); d2.push_back(2); d2.push_back(3); d1.insert(d1.begin(), d2.begin(), d2.end()); printDeque(d1);//1 2 3 0 0 0 -20 -10 10 20 //4.删除指定迭代器对应元素 deque<int>::iterator it = d1.begin(); it += 1; d1.erase(it); printDeque(d1);//1 3 0 0 0 -20 -10 10 20 //5,按照区间方式删除 d1.erase(d1.begin()+1,d1.end()-1); printDeque(d1);//1 20 //6.清空 d1.clear(); printDeque(d1);// } int main() { test1(); test2(); system("pause"); return 0; }
4.3.5 deque数据存取
-
功能:对deque中的数据进行存取操作
-
函数原型
operator[]; //返回索引[]所指的数据 at(int idx); //返回索引idx所指的数据 front(); //返回deque中第一个数据元素 back(); //返回deque中最后一个数据元素
-
代码
#include<iostream> #include<deque> using namespace std; /* operator[]; //返回索引[]所指的数据 at(int idx); //返回索引idx所指的数据 front(); //返回deque中第一个数据元素 back(); //返回deque中最后一个数据元素 */ void test1() { deque<int> d; d.push_back(1); d.push_back(2); d.push_back(3); d.push_front(-1); d.push_front(-2); d.push_front(-3); //1.通过[]方式访问元素 for (int i = 0; i < d.size(); i++) { cout << d[i] << " ";//-3 -2 -1 1 2 3 } cout << endl; //2.通过at方式访问元素 for (int i = 0; i < d.size(); i++) { cout << d.at(i) << " ";//-3 -2 -1 1 2 3 } cout << endl; //3.访问首元素 cout << d.front() << endl;//-3 //4.访问尾元素 cout << d.back() << endl;//3 } int main() { test1(); system("pause"); return 0; }
4.3.6 deque排序
-
功能:利用算法实现对deque容器进行排序
-
函数原型
算法 sort(iterator beg,iterator end);//对[beg,end)左闭右开迭代器区间内的元素进行排序 默认升序
-
代码
#include<iostream> #include<deque> #include<vector> #include<algorithm>//标准算法头文件 using namespace std; /* 算法 sort(iterator beg,iterator end);//对[beg,end)左闭右开迭代器区间内的元素进行排序 默认升序 */ void printDeque(const deque<int>& d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout << *it << " "; } cout << endl; } void printVector(const vector<int>& v) { for (vector<int>::const_iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { deque<int> d; d.push_back(2); d.push_back(1); d.push_back(3); d.push_front(-3); d.push_front(-2); d.push_front(-1); printDeque(d);//-1 -2 -3 2 1 3 //1.排序 默认升序 //对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序 比如vector和deque sort(d.begin(), d.end()); printDeque(d);//-3 -2 -1 1 2 3 //vector排序 vector<int> v; v.push_back(2); v.push_back(1); v.push_back(3); printVector(v);//2 1 3 sort(v.begin(), v.end()); printVector(v);//1 2 3 } int main() { test1(); system("pause"); return 0; }
4.4 stack容器
4.4.1 stack常用接口
-
功能:栈容器常用的对外接口
-
函数原型
- 构造函数
stack<T> stk; //stack采用模板类实现,stack对象的默认构造形式 stack(const stack &stk); //拷贝构造函数
- 赋值操作
stack& operator=(const stack &stk); //重载等号运算符
- 数据存取
push(elem); //向栈顶添加元素 pop(); //从栈顶移除第一个元素 top(); //返回栈顶元素
- 大小操作
empty(); //判断堆栈是否为空 size(); //返回栈的大小
- 构造函数
-
代码
#include<iostream> #include<stack> using namespace std; /* //1.构造函数 stack<T> stk; //stack采用模板类实现,stack对象的默认构造形式 stack(const stack &stk); //拷贝构造函数 //2.赋值操作 stack& operator=(const stack &stk); //重载等号运算符 //3.数据存取 push(elem); //向栈顶添加元素 pop(); //从栈顶移除第一个元素 top(); //返回栈顶元素 //4.大小操作 empty(); //判断堆栈是否为空 size(); //返回栈的大小 */ void test1() { //特点:符合先进后出的数据结构 stack<int>s; s.push(10); s.push(20); s.push(30); s.push(40); cout << "栈的大小" << s.size() << endl; //只要栈不为空,查看栈顶并执行出栈操作 while (!s.empty()) { //查看栈顶元素 cout << "栈顶元素为:" << s.top() << endl; s.pop(); } cout << "栈的大小" <<s.size()<< endl; } int main() { test1(); system("pause"); return 0; }
4.5 queue容器(先进先出)
4.5.1 queue常用接口
-
功能:队列容器常用的对外接口
-
函数原型
- 构造函数
queue<T> que //queue采用模板类实现,queue对象的默认构造形式 queue(const queue &que); //拷贝构造函数
- 赋值操作
queue operator=(const queue &que) //重载等号运算符
- 数据存取
push(elem); //往队尾添加元素 pop(); //从队头移除第一个元素 front(); //返回队头第一个元素 back(); //返回队尾最后一个元素
- 大小操作
empty(); //判断队列是否为空 size(); //返回队列的大小
- 构造函数
-
代码
#include<iostream> #include<queue> #include<string> using namespace std; /* //1.构造函数 queue<T> que //queue采用模板类实现,queue对象的默认构造形式 queue(const queue &que); //拷贝构造函数 //2.赋值操作 queue operator=(const queue &que) //重载等号运算符 //3.数据存取 push(elem); //往队尾添加元素 pop(); //从队头移除第一个元素 front(); //返回队头第一个元素 back(); //返回队尾最后一个元素 //4.大小操作 empty(); //判断队列是否为空 size(); //返回队列的大小 */ class Person { public: Person(string name, int age) { this->m_Name = name; this->m_Age = age; } string m_Name; int m_Age; }; void test1() { //创建队列 queue<Person> q; //准备数据 Person p1("aaa", 1); Person p2("bbb", 2); Person p3("ccc", 3); Person p4("ddd", 4); //入队 q.push(p1); q.push(p2); q.push(p3); q.push(p4); cout << "队列大小为:" << q.size()<<endl; //判断队列不为空就查看队头和队尾 while (!q.empty()) { //查看队头 cout << "队头元素--姓名:" << q.front().m_Name << "年龄:" << q.front().m_Age << endl; //查看队尾 cout << "队尾元素--姓名:" << q.back().m_Name << "年龄:" << q.back().m_Age << endl; q.pop(); } cout << "队列大小为:" << q.size()<<endl; } int main() { test1(); system("pause"); return 0; }
4.6 list容器(双向循环链表)
4.6.1 list构造函数
-
功能:创建list容器
-
函数原型
list<T> lst; //list采用模板类实现对象的默认构造形式 list(beg,end); //构造函数将[beg,end)区间中的元素拷贝给本身 list(n,elem); //构造函数将n个elem拷贝给本身 list(const list &list); //拷贝构造函数
-
代码
#include<iostream> #include<list> using namespace std; /* list<T> lst; //list采用模板类实现对象的默认构造形式 list(beg,end); //构造函数将[beg,end)区间中的元素拷贝给本身 list(n,elem); //构造函数将n个elem拷贝给本身 list(const list &list); //拷贝构造函数 */ void printList(const list<int>& L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { //1.默认构造 list<int> L1; //添加数据 L1.push_back(1); L1.push_back(2); L1.push_back(3); printList(L1);//1 2 3 //2.区间方式构造 list<int> L2(L1.begin(),L1.end()); printList(L2);//1 2 3 //3.将n个elem给本身 list<int> L3(3, 1); printList(L3);//1 1 1 //4.拷贝构造 list<int> L4(L1); printList(L4);//1 2 3 } int main() { test1(); system("pause"); return 0; }
4.6.2 list赋值和交换
-
功能:给list容器进行赋值以及交换list容器
-
函数原型
list& operator=(const list &lst); //重载等号运算符 assign(beg,end); //将[beg,end)左闭右开区间中的数据拷贝赋值给本身 assign(n,elem); //将n个elem拷贝赋值给本身 swap(lst) //将lst与本身的元素互换
-
代码
#include<iostream> #include<list> using namespace std; /* list& operator=(const list &lst); //重载等号运算符 assign(beg,end); //将[beg,end)左闭右开区间中的数据拷贝赋值给本身 assign(n,elem); //将n个elem拷贝赋值给本身 swap(lst) //将lst与本身的元素互换 */ void printList(const list<int>& L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { list<int> L1; L1.push_back(1); L1.push_back(2); L1.push_back(3); printList(L1);//1 2 3 //1.重载等号运算符 list<int> L2; L2 = L1; printList(L2);//1 2 3 //2.区间赋值 list<int> L3; L3.assign(L2.begin(), L2.end()); printList(L3);//1 2 3 //3.赋值n个元素 list<int> L4; L4.assign(3, 1); printList(L4); //4.交换 printList(L1);//1 2 3 printList(L4);//1 1 1 L1.swap(L4); printList(L1);//1 1 1 printList(L4);//1 2 3 } int main() { test1(); system("pause"); return 0; }
4.6.3 list大小操作
-
功能:对list容器的大小进行操作
-
函数原型
size(); //返回list中元素的个数 empty(); //判断list是否为空 resize(num); //重新指定list的长度为num.若list变长,则以默认值填充新位置。如果list变短,则末尾超出list长度的元素被删除。 resize(num,elem); //重新指定list的长度为num.若list变长,则以elem填充新位置。如果list变短,则末尾超出list长度的元素被删除。
-
代码
#include<iostream> #include<list> using namespace std; /* size(); //返回list中元素的个数 empty(); //判断list是否为空 resize(num); //重新指定list的长度为num.若list变长,则以默认值填充新位置。如果list变短,则末尾超出list长度的元素被删除。 resize(num,elem); //重新指定list的长度为num.若list变长,则以elem填充新位置。如果list变短,则末尾超出list长度的元素被删除。 */ void printList(const list<int>& L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { list<int> L1; L1.push_back(1); L1.push_back(2); L1.push_back(3); printList(L1);//1 2 3 //1.返回list长度 cout << L1.size() << endl;//3 //2.判断是否为空 cout << L1.empty() << endl;//0 //3.重设长度,以默认值0填充 L1.resize(6); printList(L1);//1 2 3 0 0 0 //3.重设长度,设置默认值elem填充 L1.resize(9,-1); printList(L1);//1 2 3 0 0 0 -1 -1 -1 } int main() { test1(); system("pause"); return 0; }
4.6.4 list插入和删除
-
功能:对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,beg,end); //在pos位置插入[beg,end)左闭右开区间的数据,无返回值 erase(beg,end); //删除[beg,end)区间的数据,返回下一个数据的位置 erase(pos); //删除pos位置的数据,返回下一个数据的位置 remove(elem); //删除容器中所有与elem值匹配的元素 clear(); //移除容器的所有数据
-
代码
#include<iostream> #include<list> using namespace std; /* push_back(elem); //在容器尾部加入一个元素 pop_back(); //删除容器中最后一个元素 push_front(elem); //在容器开头插入第一个元素 pop_front(); //从容器开头移除第一个元素 insert(pos,elem); //在pos位置插elem元素的拷贝,返回新数据的位置 insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值 insert(pos,beg,end); //在pos位置插入[beg,end)左闭右开区间的数据,无返回值 erase(beg,end); //删除[beg,end)区间的数据,返回下一个数据的位置 erase(pos); //删除pos位置的数据,返回下一个数据的位置 remove(elem); //删除容器中所有与elem值匹配的元素 clear(); //移除容器的所有数据 */ void printList(const list<int>& L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { list<int> L; //1.尾插 L.push_back(1); L.push_back(2); L.push_back(3); printList(L);//1 2 3 //2.头插 L.push_front(2); L.push_front(3); printList(L);//3 2 1 2 3 //3.尾删 L.pop_back(); printList(L);//3 2 1 2 //4.尾删 L.pop_front(); printList(L);//2 1 2 //5.insert一个元素 L.insert(L.begin(),3); printList(L);//3 2 1 2 //6.inser多个元素 L.insert(++L.begin(), 2,0); printList(L);//3 0 0 2 1 2 //7.insert区间元素 L.insert(L.begin(),L.begin(), L.end()); printList(L);//3 0 0 2 1 2 3 0 0 2 1 2 //8.删除指定位置元素 L.erase(L.begin()); printList(L);//0 0 2 1 2 3 0 0 2 1 2 //9.删除指定区间元素 L.erase(++L.begin(),--L.end()); printList(L);//0 2 //10.remove指定元素 L.push_back(2); printList(L);//0 2 2 L.remove(2); printList(L);//0 //11.清空 L.clear(); printList(L);// } int main() { test1(); system("pause"); return 0; }
4.6.5 list数据存取
-
功能:对list容器中数据进行存取
-
函数原型(无[]与at访问方式因为是链表不是连续存储空间,迭代器不支持随机访问,迭代器只能一步一步的加法或减法,但不能直接跳跃访问)
front(); //返回第一个元素 back(); //返回最后一个元素
-
代码
#include<iostream> #include<list> using namespace std; /* front(); //返回第一个元素 back(); //返回最后一个元素 */ void test1() { list<int> L1; L1.push_back(1); L1.push_back(2); L1.push_back(3); //1.返回第一个元素 cout << L1.front() << endl;//1 //2.返回第二个元素 cout << L1.back() << endl;//3 } int main() { test1(); system("pause"); return 0; }
4.6.6 list反转和排序
-
功能:将容器中的元素反转以及将容器中的数据进行排序
-
函数原型
reverse(); //反转链表 sort(); //链表排序
-
代码
#include<iostream> #include<list> using namespace std; /* reverse(); //反转链表 sort(); //链表排序 */ void printList(const list<int>& L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } bool myCompare(int v1,int v2) { //降序 让第一个数>第二个数 return v1 > v2; } void test1() { list<int> L1; L1.push_back(1); L1.push_back(2); L1.push_back(3); printList(L1);//1 2 3 //1.反转 L1.reverse(); printList(L1);//3 2 1 //2.排序 //所有不支持随机访问迭代器的容器,不可以使用标准算法 //不支持随机访问迭代器的容器,内部会提供对应一些算法 L1.sort();//默认升序排序 printList(L1);//1 2 3 L1.sort(myCompare); printList(L1);//3 2 1 } int main() { test1(); system("pause"); return 0; }
4.7 set/multiset容器
4.7.1 set构造和赋值
-
功能:创建set容器以及赋值
-
函数原型
构造: set<T> st; //默认构造函数 set(const set<T> &st); //拷贝构造函数 赋值: set &operator=(const set &st); //重载等号操作符
-
代码
#include<iostream> #include<set> using namespace std; /* 构造: set<T> st; //默认构造函数 set(const set<T> &st); //拷贝构造函数 赋值: set &operator=(const set &st); //重载等号操作符 */ void printSet(const set<int>& s) { for (set<int>::const_iterator it = s.begin(); it != s.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { //1.默认构造 set<int> s1; //插入数据只有insert方式 s1.insert(1); s1.insert(3); s1.insert(2); s1.insert(4); s1.insert(3); //遍历容器 printSet(s1);//1 2 3 4 //2.拷贝构造 set<int> s2(s1); printSet(s2);//1 2 3 4 //3.等号赋值 set<int> s3; s3 = s2; printSet(s3);//1 2 3 4 } int main() { test1(); system("pause"); return 0; }
4.7.2 set大小和交换
-
功能:统计set容器大小以及交换set容器
-
函数原型
size(); //返回容器中元素的数目 empty(); //判断容器是否为空 swap(st); //交换两个集合容器
-
代码
#include<iostream> #include<set> using namespace std; //set容器 大小和交换 /* size(); //返回容器中元素的数目 empty(); //判断容器是否为空 swap(st); //交换两个集合容器 */ void printSet(const set<int>& s) { for (set<int>::const_iterator it = s.begin(); it != s.end(); it++) { cout << *it << " "; } cout << endl; } //大小 void test1() { set<int> s1; s1.insert(1); s1.insert(3); s1.insert(2); s1.insert(4); printSet(s1);//1 2 3 4 cout << s1.size() << endl;//4 cout << s1.empty()<< endl;//0 //交换 set<int> s2; s2.insert(1); s2.insert(3); s2.insert(2); s2.insert(4); s2.insert(6); s2.insert(5); printSet(s2);//1 2 3 4 5 6 s1.swap(s2); printSet(s1);//1 2 3 4 5 6 printSet(s2);//1 2 3 4 } int main() { test1(); system("pause"); return 0; }
4.7.3 set插入和删除
-
功能:set容器进行插入数据和删除数据
-
函数原型
insert(elem); //在容器中插入元素 erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器 erase(beg,end); //删除区间[beg,end)的所有元素,返回下一个元素的迭代器 erase(elem); //删除容器中值为elem的元素 clear(); //清除所有元素
-
代码
#include<iostream>
#include<set>
using namespace std;
/*
insert(elem); //在容器中插入元素
erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg,end); //删除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(elem); //删除容器中值为elem的元素
clear(); //清除所有元素
*/
void printSet(const set<int>& s)
{
for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test1()
{
set<int> s1;
//1.插入
s1.insert(2);
s1.insert(1);
s1.insert(3);
s1.insert(4);
s1.insert(5);
s1.insert(6);
printSet(s1); //1 2 3 4 5 6
//2.删除pos迭代器指向的位置
s1.erase(s1.begin());
printSet(s1); //2 3 4 5 6
//3.删除区间
s1.erase(++s1.begin(),--s1.end());
printSet(s1); //2 6
//4.删除元素
s1.erase(2);
printSet(s1); //6
//4.清空
s1.clear();
printSet(s1); //
}
int main()
{
test1();
system("pause");
return 0;
}
4.7.4 set查找和统计
-
功能
-
函数原型
find(key); //查找key是否存在,返回该键的元素的迭代器;若不存在,返回set.end(); count(key); //统计key的元素个数//对于set容器统计结果要么是0要么是1
-
代码
#include<iostream> #include<set> using namespace std; /* find(key); //查找key是否存在,返回该键的元素的迭代器;若不存在,返回set.end(); count(key); //统计key的元素个数 */ void test1() { set<int> s1; s1.insert(1); s1.insert(2); s1.insert(3); //1.查找 set<int>::iterator pos = s1.find(3); if (pos != s1.end()) { cout << "找到" <<(*pos)<< endl;//找到3 } else { cout << "未找到" << endl; } //2.统计 cout << s1.count(3) << endl;//1 cout << s1.count(6) << endl;//0 } int main() { test1(); system("pause"); return 0; }
4.7.5 set和multiset区别
-
区别:
- set不可以插入重复数据,而multiset可以(其实可以set可以插入重复数据,只是重复数据不生效而已)
- set插入数据的同时会返回插入结果,表示插入是否成功
- multiset不会检测数据,因此可以插入重复数据
-
代码
#include<iostream> #include<set> using namespace std; void printMultiset(const multiset<int> ms) { for (multiset<int>::const_iterator it = ms.begin(); it != ms.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { set<int> s; pair<set<int>::iterator, bool> ret = s.insert(10); if (ret.second) { cout << "第一次插入成功" << endl;//第一次插入成功 } else { cout << "第一次插入失败" << endl; } ret = s.insert(10); if (ret.second) { cout << "第二次插入成功" << endl; } else { cout << "第二次插入失败" << endl;//第二次插入失败 } multiset<int> ms; ms.insert(1); ms.insert(1); ms.insert(2); ms.insert(2); ms.insert(3); ms.insert(3); printMultiset(ms);//1 1 2 2 3 3 } int main() { test1(); system("pause"); return 0; }
4.7.6 pair对组
-
功能:成对出现的数据,利用对组可以返回两个数据
-
创建方式
pair<type,type> p(value1,value2); pair<type,type> p = make_pair(value1,value2);
-
代码
#include<iostream> #include<string> using namespace std; /* pair<type,type> p(value1,value2); pair<type,type> p = make_pair(value1,value2); */ void test1() { //第一种方式创建对组 pair<string, int>p1("Tom", 20); cout << "姓名:" << p1.first << endl;//Tom cout << "年龄:" << p1.second << endl;//20 //第二种方式创建对组 pair<string, int>p2 = make_pair("Tom", 20); cout << "姓名:" << p2.first << endl;//Tom cout << "年龄:" << p2.second << endl;//20 } int main() { test1(); system("pause"); return 0; }
4.7.7 set容器排序
-
代码(利用set存放内置数据类型并用仿函数指定排序规则)
#include<iostream> #include<set> using namespace std; class Mycompare { public: bool operator()(int v1,int v2) const { return v1 > v2; } }; void printSet(const set<int,Mycompare>& s) { for (set<int,Mycompare>::const_iterator it = s.begin(); it != s.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { set<int, Mycompare> s1; s1.insert(1); s1.insert(4); s1.insert(5); s1.insert(2); s1.insert(3); s1.insert(6); printSet(s1); } int main() { test1(); system("pause"); return 0; }
-
代码(利用set存放自定义数据类型并用仿函数指定排序规则)
#include<iostream> #include<string> #include<set> using namespace std; class Person { public: Person(string name, int age) { this->m_Name = name; this->m_Age = age; } string m_Name; int m_Age; }; class comparePerson { public: bool operator()(const Person& p1, const Person& p2) const { return p1.m_Age > p2.m_Age; } }; void printSet(const set<Person,comparePerson>& s) { for (set<Person,comparePerson>::const_iterator it = s.begin(); it != s.end(); it++) { cout << (*it).m_Name << " "; cout << (*it).m_Age <<endl; } cout << endl; } void test1() { set<Person,comparePerson> s; Person p1("a", 1); Person p4("d", 4); Person p5("e", 5); Person p2("b", 2); Person p3("c", 3); Person p6("f", 6); s.insert(p1); s.insert(p2); s.insert(p3); s.insert(p4); s.insert(p5); s.insert(p6); printSet(s); } int main() { test1(); system("pause"); return 0; }
4.8 map/multimap容器(按照key值进行默认排序)
4.8.1 map构造和赋值
-
功能:对map容器进行构造和赋值
-
函数原型
构造: map<T1,T2> mp; //map默认构造函数 map(const map &mp); //拷贝构造函数 赋值 map &operator=(const map &mp); //重载等号操作符
-
代码
#include<iostream> #include<map> using namespace std; /* 构造: map<T1,T2> mp; //map默认构造函数 map(const map &mp); //拷贝构造函数 赋值 map &operator=(const map &mp); //重载等号操作符 */ void printMap(const map<int, int>& m) { for (map<int, int>::const_iterator it = m.begin(); it != m.end(); it++) { cout << "key="<<(*it).first << " "; cout << "value=" << (*it).second << endl; } cout << endl; } void test1() { //1.默认构造 map<int, int> m1; m1.insert(pair<int, int>(1, 10));//匿名对组 //插入数据要以对组方式插入数据 m1.insert(pair<int, int>(3, 30)); m1.insert(pair<int, int>(2, 20)); printMap(m1); //2.拷贝构造 map<int, int> m2(m1); printMap(m2); //3.重载等号赋值 map<int, int> m3; m3 = m2; printMap(m3); } int main() { test1(); system("pause"); return 0; }
4.8.2 map大小和交换
-
功能:统计map容器大小以及交换map容器
-
函数原型
size(); //返回容器中元素的数目 empty(); //判断容器是否为空 swap(mp); //交换两个map容器
-
代码
#include<iostream> #include<map> using namespace std; /* size(); //返回容器中元素的数目 empty(); //判断容器是否为空 swap(mp); //交换两个map容器 */ void printMap(const map<int,int> &m) { for (map<int, int>::const_iterator it = m.begin(); it != m.end(); it++) { cout << (*it).first << " "; cout << (*it).second << endl; } cout << endl; } void test1() { map<int, int> m1; m1.insert(pair<int, int>(1, 10)); m1.insert(pair<int, int>(2, 20)); m1.insert(pair<int, int>(3, 30)); printMap(m1); //1.判断是否为空 cout << m1.empty() << endl; //0; //2.返回容器大小 cout << m1.size() << endl;//3 //3.交换 map<int, int> m2; m2.insert(pair<int, int>(-1, -10)); m2.insert(pair<int, int>(-2, -20)); m2.insert(pair<int, int>(-3, -30)); printMap(m2); m1.swap(m2); printMap(m1); printMap(m2); } int main() { test1(); system("pause"); return 0; }
4.8.3 map插入和删除
-
功能:map容器进行插入数据和删除数据
-
函数原型
insert(elem); //在容器中插入元素 erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器 erase(beg,end); //删除区间[beg,end)的所有元素,返回下一个元素的迭代器 erase(key); //删除容器中值为key的元素 clear(); //清除所有元素
-
代码
#include<iostream> #include<map> using namespace std; /* insert(elem); //在容器中插入元素 erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器 erase(beg,end); //删除区间[beg,end)的所有元素,返回下一个元素的迭代器 erase(key); //删除容器中值为key的元素 clear(); //清除所有元素 */ void printMap(const map<int, int>& m) { for (map<int, int>::const_iterator it = m.begin(); it != m.end(); it++) { cout << (*it).first << " "; cout << (*it).second << endl; } cout << endl; } void test1() { map<int, int> m1; //1.插入 //第一种 m1.insert(pair<int, int>(1, 10)); //第二种 m1.insert(make_pair(2, 20)); //第三种 m1.insert(map<int, int>::value_type(3, 30)); //第四种 m1[4] = 40; //[]不建议用于插入, 用途:利用key访问到value cout << m1[4] << endl;//40 printMap(m1); //2.通过迭代器删除 m1.erase(m1.begin()); printMap(m1); //3.通过区间删除 m1.erase(++m1.begin(),--m1.end()); printMap(m1); //4.通过key值删除 m1.erase(2); printMap(m1); //5.清空 m1.clear(); printMap(m1);// } int main() { test1(); system("pause"); return 0; }
4.8.4 map查找和统计
-
功能:对map容器进行查找数据以及统计数据(包括multimap)
-
函数原型
find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回map.end(); count(key); //统计key的元素个数
-
代码
#include<iostream> #include<map> using namespace std; /* find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回map.end(); count(key); //统计key的元素个数 */ void printMultimap(const multimap<int, int>& m) { for (multimap<int, int>::const_iterator it = m.begin(); it != m.end(); it++) { cout << (*it).first << " "; cout << (*it).second << endl; } cout << endl; } void test1() { //1.查找 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)); map<int,int>::iterator pos=m.find(4); if (pos != m.end()) { cout << "查找到了元素key=" << (*pos).first << " value="<<(*pos).second << endl; } else { cout << "未找到元素" << endl;//未找到元素 } //2.统计 //map不允许插入重复的key cout << m.count(3) << endl;//1 //multimap允许插入重复的key multimap<int, int> mm; mm.insert(pair<int, int>(1, 10)); mm.insert(pair<int, int>(1, 20)); mm.insert(pair<int, int>(2, 20)); mm.insert(pair<int, int>(2, 40)); mm.insert(pair<int, int>(3, 30)); mm.insert(pair<int, int>(3, 60)); printMultimap(mm); cout << mm.count(3) << endl;//2 } int main() { test1(); system("pause"); return 0; }
4.8.5 map容器排序
-
代码(利用仿函数自定义排序规则)
#include<iostream> #include<map> using namespace std; //仿函数 class MyCompare { public: bool operator()(int v1,int v2) const { //降序排序 return v1 > v2; } }; void printMap(const map<int, int,MyCompare>& m) { for (map<int, int,MyCompare>::const_iterator it = m.begin(); it != m.end(); it++) { cout << (*it).first << " "; cout << (*it).second << endl; } cout << endl; } void test1() { map<int, int,MyCompare> m; m.insert(make_pair(1, 10)); m.insert(make_pair(4, 40)); m.insert(make_pair(5, 50)); m.insert(make_pair(2, 20)); m.insert(make_pair(3, 30)); m.insert(make_pair(6, 60)); printMap(m); } int main() { test1(); system("pause"); return 0; }
5.STL函数对象
-
概念
- 重载函数调用操作符的类,其对象常称为函数对象
- 函数对象使用重载的()时,行为类似函数调用,也叫仿函数
-
本质:函数对象(仿函数)是一个类,不是一个函数
-
函数对象使用代码
#include<iostream> using namespace std; //函数对象(仿函数) //1.函数对象在使用时可以像普通函数那样调用,可以有参数也可以有返回值 class MyAdd { public: int operator()(int v1, int v2) { return v1 + v2; } }; //2.函数对象超出普通函数的概念,函数对象可以有自己的状态 class MyPrint { public: MyPrint() { this->count = 0; } void operator()(string test) { cout << test << endl; this->count++; } int count;//内部自己状态 }; void test1() { MyAdd myAdd; cout<<myAdd(10, 20)<<endl;//30 } void test2() { MyPrint myPrint; myPrint("Hello World");//Hello World myPrint("Hello World");//Hello World myPrint("Hello World");//Hello World cout << "myPrint调用次数为:" <<myPrint.count<<endl;//3 } //3、函数对象可以作为参数传递 void doPrint(MyPrint& mp, string test) { mp(test); } void test3() { MyPrint myPrint; doPrint(myPrint, "Hello C++");//Hello C++ } int main() { test1(); test2(); test3(); system("pause"); return 0; }
6 谓词
- 概念:返回bool类型的仿函数称为谓词
6.1 一元谓词
-
定义:operator()接受一个参数并且返回bool类型的仿函数称为一元谓词
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; //一元谓词 class GreaterFive { public: bool operator()(int val) { return val > 5; } }; void test1() { vector<int> v1; v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.push_back(5); v1.push_back(6); //查找容器中有没有大于5的数字 //传入匿名函数对象 vector<int>::iterator it=find_if(v1.begin(), v1.end(), GreaterFive()); if (it == v1.end()) { cout << "未找到" << endl; } else { cout << "找到" << *it << endl; } } int main() { test1(); system("pause"); return 0; }
6.2 二元谓词
-
定义:operator()接受两个参数并且返回bool类型的仿函数称为二元谓词
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; //二元谓词 class MyCompare { public: bool operator()(int val1, int val2) { return val1 > val2; } }; void printVector(const vector<int> v) { for (vector<int>::const_iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { vector<int> v; v.push_back(2); v.push_back(1); v.push_back(3); v.push_back(5); v.push_back(4); v.push_back(6); sort(v.begin(), v.end()); printVector(v);//1 2 3 4 5 6 //使用函数对象 改变算法策略为从大到小 sort(v.begin(), v.end(), MyCompare()); printVector(v);//6 5 4 3 2 1 } int main() { test1(); system("pause"); return 0; }
7 内建函数对象
- 概念:STL内建了一些函数对象
- 分类:
- 算术仿函数
- 关系仿函数
- 逻辑仿函数
7.1 算术仿函数
-
功能:实现四则运算
-
函数原型
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 modules<T> //取模仿函数(二元仿函数) template<class T> T negate<T> //取反仿函数(一元仿函数)
-
代码
#include<iostream> #include<functional>//内建函数对象头文件 using namespace std; /* 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 modules<T> //取模仿函数(二元仿函数) template<class T> T negate<T> //取反仿函数(一元仿函数) */ //negate 一元仿函数 取反仿函数 void test1() { negate<int> n; cout << n(50) << endl;//-50 } //plus 二元仿函数 加法 void test2() { plus<int> p; cout << p(10, 20) << endl;//30 } int main() { test1(); test2(); system("pause"); return 0; }
7.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> //小于等于
-
代码
#include<iostream> #include<vector> #include<functional> #include<algorithm> using namespace std; /* 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> //小于等于 */ void printVector(const vector<int> &v) { for (vector<int>::const_iterator it = v.begin(); it != v.end(); it++) { cout << *it << endl; } cout << endl; } void test1() { vector<int> v; v.push_back(1); v.push_back(4); v.push_back(6); v.push_back(5); v.push_back(2); v.push_back(3); printVector(v);//1 4 6 5 2 3 sort(v.begin(), v.end(), greater<int>()); printVector(v);//6 5 4 3 2 1 } int main() { test1(); system("pause"); return 0; }
7.3 逻辑仿函数
-
功能:实现逻辑运算
-
仿函数原型
template<class T> bool logical_and<T> //逻辑与 template<class T> bool logical_or<T> //逻辑或 template<class T> bool logical_not<T> //逻辑非
-
代码
#include<iostream> #include<vector> #include<functional> #include<algorithm> using namespace std; /* template<class T> bool logical_and<T> //逻辑与 template<class T> bool logical_or<T> //逻辑或 template<class T> bool logical_not<T> //逻辑非 */ void printVector(const vector<bool > & v) { for (vector<bool>::const_iterator it = v.begin(); it != v.end(); it++) { cout << *it << endl; } cout << endl; } void test1() { vector<bool> v; v.push_back(true); v.push_back(false); v.push_back(true); v.push_back(false); v.push_back(true); v.push_back(false); printVector(v);//1 0 1 0 1 0 //利用逻辑非将容器v搬运到容器v2中,并执行取反操作 vector<bool> v2; v2.resize(v.size()); transform(v.begin(), v.end(), v2.begin(), logical_not<bool>()); printVector(v2);//0 1 0 1 0 1 } int main() { test1(); system("pause"); return 0; }
8 STL常用算法
- :所有STL文件中最大的一个,范围涉及到比较、交换、查找、遍历操作、复制、修改等等
- :体积很小,只包括几个在序列上面进行简单数学运算的模板函数
- :定义了一些模板类,用以声明函数对象
8.1常用遍历算法
8.1.1 for_each
-
功能:实现容器遍历
-
函数原型
for_each(iterator beg,iterator end,_func); beg:起始迭代器 end:结束迭代器 _func函数或者函数对象
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; /* for_each(iterator beg,iterator end,_func); beg:起始迭代器 end:结束迭代器 _func函数或者函数对象 */ //普通函数(传函数名) void print1(int val) { cout << val << endl; } //仿函数(传函数对象) class print2 { public: void operator()(int val) { cout << val << endl; } }; void test1() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); for_each(v.begin(), v.end(), print1);//1 2 3 4 5 6 cout << endl; for_each(v.begin(), v.end(), print2());//1 2 3 4 5 6 cout << endl; } int main() { test1(); system("pause"); return 0; }
8.1.2 transform
- 功能:搬运容器到另一个容器中
- 函数原型
transform(iterator beg1,iterator end1,itreator beg2,_func);
beg1:源容器开始迭代器
end1:源容器结束迭代器
beg2:目标容器开始迭代器
_func函数或者函数对象
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; /* transform(iterator beg1,iterator end1,itreator beg2,_func); beg1:源容器开始迭代器 end1:源容器结束迭代器 beg2:目标容器开始迭代器 _func函数或者函数对象 */ class Transform { public: int operator()(int v) { return v*(-1); } }; class print1 { public: void operator()(int val) { cout << val << endl; } }; void test1() { vector<int> v1;//源容器 v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.push_back(5); v1.push_back(6); vector<int> v2;//目标容器 (需要提前开辟空间) v2.resize(v1.size()); transform(v1.begin(), v1.end(), v2.begin(), Transform()); for_each(v2.begin(), v2.end(), print1());//-1 -2 -3 -4 -5 -6 } int main() { test1(); system("pause"); return 0; }
8.2常用查找算法
8.2.1 find
-
功能:查找指定元素,找到返回指定元素的迭代器,找不到返回结束迭代器end()
-
函数原型
find(iterator beg,iterator end,value); beg:开始迭代器 end:结束迭代器 valuec:查找的元素
-
代码
#include<iostream> #include<vector> #include<string> #include<algorithm> using namespace std; /* find(iterator beg,iterator end,value); beg:开始迭代器 end:结束迭代器 valuec:查找的元素 */ //查找内置数据类型 void test1() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); vector<int>::iterator it=find(v.begin(), v.end(), 3); if (it != v.end()) { cout <<"找到:" <<* it << endl; } else { cout << "未找到" << endl; } } //查找自定义数据类型 class Person { public: Person(string name, int age) { this->m_Name = name; this->m_Age = age; } //重载==让底层find知道如何对比person数据类型 bool operator==(const Person& p) { if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) { return true; } else { return false; } } string m_Name; int m_Age; }; void test2() { vector<Person> v; Person p1("a", 1); Person p2("b", 2); Person p3("c", 3); Person p4("d", 4); Person p5("e", 5); Person p6("f", 6); v.push_back(p1); v.push_back(p2); v.push_back(p3); v.push_back(p4); v.push_back(p5); v.push_back(p6); vector<Person>::iterator it = find(v.begin(), v.end(), p3); if (it != v.end()) { cout << "找到:" << (*it).m_Name<< " " << (*it).m_Age<<endl; } else { cout << "未找到" << endl; } } int main() { test1(); test2(); system("pause"); return 0; }
8.2.2 find_if
-
功能:按条件查找元素
-
函数原型
find_if(iterator beg,iterator end,_Pred); //beg:开始迭代器 //end:结束迭代器 _Pred:函数或谓词(返回bool类型的仿函数)
-
代码
#include<iostream> #include<string> #include<vector> #include<algorithm> using namespace std; /* find_if(iterator beg,iterator end,_Pred); //beg:开始迭代器 //end:结束迭代器 _Pred:函数或谓词(返回bool类型的仿函数) */ //1.查找内置数据类型 class GreaterFive { public: bool operator()(int val) { return val > 5; } }; void test1() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive()); if (it == v.end()) { cout << "未找到" << endl; } else { cout << "找到大于5的数字为" << *it << endl;//找到大于5的数字为6 } } //2.查找自定义数据类型 class Person { public: Person(string name, int age) { this->m_Name = name; this->m_Age = age; } string m_Name; int m_Age; }; class Greater3 { public: bool operator()(Person& p) { return p.m_Age > 3; } }; void test2() { vector<Person> v; Person p1("a", 1); Person p2("b", 2); Person p3("c", 3); Person p4("d", 4); Person p5("e", 5); Person p6("f", 6); v.push_back(p1); v.push_back(p2); v.push_back(p3); v.push_back(p4); v.push_back(p5); v.push_back(p6); //找年龄大于3的人 vector<Person>::iterator it = find_if(v.begin(), v.end(), Greater3()); if (it == v.end()) { cout << "未找到" << endl; } else { cout << "找到年龄大于3的人为" << (*it).m_Name << " "<<(*it).m_Age<<endl;//找到年龄大于3的人为d 4 } } int main() { test1(); test2(); system("pause"); return 0; }
8.2.3 adjacent_find
-
功能:查找相邻重复元素
-
函数原型
adjacent_find(iterator beg,iterator end); beg:开始迭代器 end:结束迭代器
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; /* adjacent_find(iterator beg,iterator end); beg:开始迭代器 end:结束迭代器 */ void test1() { vector<int> v; v.push_back(1); v.push_back(3); v.push_back(2); v.push_back(2); v.push_back(1); v.push_back(3); vector<int> ::iterator it=adjacent_find(v.begin(), v.end()); if (it == v.end()) { cout << "未找到" << endl; }else { cout << "找到相邻重复元素" << *it << endl; //找到相邻重复元素2 } } int main() { test1(); system("pause"); return 0; }
8.2.4 binary_search
-
功能:查找有序序列中指定元素是否存在
-
函数原型
bool binary_search(iterator beg,iterator end,value) beg:开始迭代器 end:结束迭代器 value:查找的元素
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; /* bool binary_search(iterator beg,iterator end,value) beg:开始迭代器 end:结束迭代器 value:查找的元素 */ void test1() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); //查找容器中是否有3 cout<<binary_search(v.begin(), v.end(), 3)<<endl;//1 } int main() { test1(); system("pause"); return 0; }
8.2.5 count
-
功能:统计元素个数(当统计自定义数据类型时需要重载operator==)
-
函数原型
count(iterator beg,iterator end,value); beg:开始迭代器 end:结束迭代器 value:统计的元素
-
代码
#include<iostream> #include<string> #include<vector> #include<algorithm> using namespace std; /* count(iterator beg,iterator end,value); beg:开始迭代器 end:结束迭代器 value:统计的元素 */ //1.统计内置数据类型 void test1() { vector<int> v; v.push_back(1); v.push_back(1); v.push_back(2); v.push_back(2); v.push_back(3); v.push_back(3); cout<<count(v.begin(), v.end(), 3)<<endl;//2 } //2.统计自定义数据类型 class Person { public: Person(string name, int age) { this->m_Name = name; this->m_Age = age; } string m_Name; int m_Age; //重载== bool operator==(const Person & p) { return this->m_Age == p.m_Age; } }; void test2() { vector<Person> v; Person p1("a", 1); Person p2("b", 1); Person p3("c", 2); Person p4("d", 2); Person p5("e", 3); Person p6("f", 3); v.push_back(p1); v.push_back(p2); v.push_back(p3); v.push_back(p4); v.push_back(p5); v.push_back(p6); cout<<count(v.begin(), v.end(), p5)<<endl;//2 } int main() { test1(); test2(); system("pause"); return 0; }
8.2.6 count_if
-
功能:按条件统计元素个数
-
函数原型
count_if(iterator beg,iterator end,_Pred) beg:开始迭代器 end:结束迭代器 _Pred:谓词
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; /* count_if(iterator beg,iterator end,_Pred) beg:开始迭代器 end:结束迭代器 _Pred:谓词 */ //1.统计内置数据类型 class Greater3 { public: bool operator()(int val) { return val > 3; } }; void test1() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); cout<<count_if(v.begin(), v.end(), Greater3())<<endl;//3 } //2.统计自定义数据类型 class Person { public: Person(string name, int age) { this->m_Name = name; this->m_Age = age; } string m_Name; int m_Age; }; class AgeGreater3 { public: bool operator()(const Person& p) { return p.m_Age > 3; } }; void test2() { vector<Person> v; Person p1("a", 1); Person p2("b", 2); Person p3("c", 3); Person p4("d", 4); Person p5("e", 5); Person p6("f", 6); v.push_back(p1); v.push_back(p2); v.push_back(p3); v.push_back(p4); v.push_back(p5); v.push_back(p6); cout << count_if(v.begin(), v.end(), AgeGreater3()) << endl;//3 } int main() { test1(); test2(); system("pause"); return 0; }
8.3 常用排序算法
8.3.1 sort
-
功能:对容器内元素进行排序
-
函数原型
sort(iterator beg,iterator end,_Pred); beg:开始迭代器 end:结束迭代器 _Pred:谓词
-
代码
#include<iostream> #include<vector> #include<functional> #include<algorithm> using namespace std; /* sort(iterator beg,iterator end,_Pred); beg:开始迭代器 end:结束迭代器 _Pred:谓词 */ void print1(int val) { cout << val << endl; } void test1() { vector<int> v; v.push_back(1); v.push_back(4); v.push_back(5); v.push_back(2); v.push_back(3); v.push_back(6); sort(v.begin(), v.end()); for_each(v.begin(), v.end(), print1);//1 2 3 4 5 6 sort(v.begin(), v.end(),greater<int>());//使用内建函数对象降序排序 for_each(v.begin(), v.end(), print1);//6 5 4 3 2 1 } int main() { test1(); system("pause"); return 0; }
8.3.1 random_shuffle
-
功能:对容器内元素进行排序
-
函数原型
random_shuffle(iterator_beg,iterator end); //beg:开始迭代器 //end:结束迭代器
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; /* random_shuffle(iterator_beg,iterator end); //beg:开始迭代器 //end:结束迭代器 */ void myPrint(int val) { cout << val << endl; } void test1() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); random_shuffle(v.begin(), v.end()); for_each(v.begin(), v.end(),myPrint);//5 2 4 3 1 6 } int main() { test1(); system("pause"); return 0; }
8.3.1 merge(合并的两个容器必须都是有序序列,合并完后目标容器也是有序序列)
-
功能:两个容器元素合并,并存储到另一容器中
-
函数原型
merge(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest); beg1:容器1开始迭代器 end1:容器1结束迭代器 beg1:容器2开始迭代器 end1:容器2结束迭代器 dest:目标容器开始迭代器
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; /* merge(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest); beg1:容器1开始迭代器 end1:容器1结束迭代器 beg1:容器2开始迭代器 end1:容器2结束迭代器 dest:目标容器开始迭代器 */ void myPrint(int val) { cout << val << endl; } void test1() { vector<int> v1; v1.push_back(1); v1.push_back(2); v1.push_back(3); vector<int> v2; v2.push_back(1); v2.push_back(2); v2.push_back(3); v2.push_back(4); v2.push_back(5); v2.push_back(6); v2.push_back(7); v2.push_back(8); v2.push_back(9); //目标容器 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);//1 1 2 2 3 3 4 5 6 7 8 9 } int main() { test1(); system("pause"); return 0; }
8.3.1 reverse
-
功能:将容器内元素进行反转
-
函数原型
reverse(iterator beg,iterator end); beg:开始迭代器 end:结束迭代器
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; /* reverse(iterator beg,iterator end); beg:开始迭代器 end:结束迭代器 */ void myPrint(int val) { cout << val << endl; } void test1() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); reverse(v.begin(), v.end()); for_each(v.begin(), v.end(), myPrint);//3 2 1 } int main() { test1(); system("pause"); return 0; }
8.4 常用拷贝和替换算法
8.4.1 copy
-
功能:容器内指定范围内的元素拷贝到另一个容器中
-
函数原型
copy(iterator beg,iterator end,iterator dest); beg:开始迭代器 end:结束迭代器 dest:目标起始迭代器
-
代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
/*
copy(iterator beg,iterator end,iterator dest);
beg:开始迭代器
end:结束迭代器
dest:目标起始迭代器
*/
void myPrint(int val)
{
cout << val << endl;
}
void test1()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
vector<int> vTarget;
vTarget.resize(v.size());
copy(v.begin(), v.end(), vTarget.begin());
for_each(vTarget.begin(), vTarget.end(), myPrint);//1 2 3
}
int main()
{
test1();
system("pause");
return 0;
}
8.4.1 replace
-
功能:将容器内指定范围的旧元素修改为新元素
-
函数原型
replace(iterator beg,iterator end,oldvalue,newvalue) beg:开始迭代器 end:结束迭代器 oldvalue:旧元素 newvalue:新元素
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; /* replace(iterator beg,iterator end,oldvalue,newvalue) beg:开始迭代器 end:结束迭代器 oldvalue:旧元素 newvalue:新元素 */ class myPrint { public: void operator()(int val) { cout << val << endl; } }; void test1() { vector<int> v; v.push_back(1); v.push_back(1); v.push_back(2); v.push_back(2); v.push_back(3); v.push_back(3); replace(v.begin(), v.end(), 3, 6); for_each(v.begin(), v.end(), myPrint());//1 1 2 2 6 6 } int main() { test1(); system("pause"); return 0; }
8.4.1 replace_if
- 功能:将区间内满足条件的元素,替换成指定元素
- 函数原型
replace_if(iterator beg,iterator end,_Pred,newvalue)
beg:开始迭代器
end:结束迭代器
_Pred:谓词
newvalue:替换的新元素
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; /* replace_if(iterator beg,iterator end,_Pred,newvalue) beg:开始迭代器 end:结束迭代器 _Pred:谓词 newvalue:替换的新元素 */ void myPrint(int val) { cout << val << endl; } class Greater2 { public: bool operator()(int val) { return val>=2; } }; void test1() { vector<int> v; v.push_back(1); v.push_back(1); v.push_back(2); v.push_back(2); v.push_back(3); v.push_back(3); replace_if(v.begin(), v.end(), Greater2(), 6); for_each(v.begin(), v.end(), myPrint);//1 1 6 6 6 6 } int main() { test1(); system("pause"); return 0; }
8.4.1 swap
-
功能:互换两个容器的元素(这两个容器长度可以不同,但是两个容器类型需要相同)
-
函数原型
swap(container c1,container c2); c1:容器1名称 c2:容器2名称
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; /* swap(container c1,container c2); c1:容器1名称 c2:容器2名称 */ class myPrint { public: void operator()(int val) { cout << val << endl; } }; void test1() { vector<int> v1; v1.push_back(1); v1.push_back(2); v1.push_back(3); vector<int> v2; v2.push_back(4); v2.push_back(5); v2.push_back(6); v2.push_back(7); v2.push_back(8); v2.push_back(9); swap(v1, v2); for_each(v1.begin(), v1.end(), myPrint());//4 5 6 7 8 9 for_each(v2.begin(), v2.end(), myPrint());//1 2 3 } int main() { test1(); system("pause"); return 0; }
8.5 常用算术生成算法(小型算法,需要包含头文件)
8.5.1 accumulate
-
功能:计算区间内容器元素累计总和
-
函数原型
accumulate(iterator beg,iterator end,value); beg:开始迭代器 end:结束迭代器 value:总和初始值,一般设为0
-
代码
#include<iostream> #include<vector> #include<numeric> using namespace std; /* accumulate(iterator beg,iterator end,value); beg:开始迭代器 end:结束迭代器 value:总和初始值,一般设为0 */ void test1() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); cout << accumulate(v.begin(), v.end(), 0) << endl;//6 } int main() { test1(); system("pause"); return 0; }
8.5.1 fill
-
功能:向容器中填充指定的元素
-
函数原型
fill(iterator beg,iterator end,value); beg:开始迭代器 end:结束迭代器 value:填充的值
-
代码
#include<iostream> #include<vector> #include<algorithm> #include<numeric> using namespace std; /* fill(iterator beg,iterator end,value); beg:开始迭代器 end:结束迭代器 value:填充的值 */ class myPrint { public: void operator()(int val) { cout<<val<<endl; } }; void test1() { vector<int> v; v.resize(3); fill(v.begin(), v.end(), 3); for_each(v.begin(), v.end(), myPrint());//3 3 3 } int main() { test1(); system("pause"); return 0; }
8.6 常用集合算法
8.6.1 set_intersection(求交集的两个容器必须是有序序列)
-
功能:求两个容器的交集,返回目标容器最后一个含元素的迭代器位置
-
函数原型
set_intersection(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest); beg1:容器1开始迭代器 end1:容器1结束迭代器 beg1:容器2开始迭代器 end1:容器2结束迭代器 dest:目标容器开始迭代器
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; /* set_intersection(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest); beg1:容器1开始迭代器 end1:容器1结束迭代器 beg1:容器2开始迭代器 end1:容器2结束迭代器 dest:目标容器开始迭代器 */ class myPrint { public: void operator()(int val) { cout << val << endl; } }; void test1() { vector<int> v1; v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.push_back(5); v1.push_back(6); vector<int> v2; v2.push_back(4); v2.push_back(5); v2.push_back(6); v2.push_back(7); v2.push_back(8); v2.push_back(9); 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());//4 5 6 } int main() { test1(); system("pause"); return 0; }
8.6.2 set_union(求并集的两个容器必须是有序序列)
-
功能:求两个容器的并集,返回目标容器最后一个含元素的迭代器位置
-
函数原型
set_union(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest); beg1:容器1开始迭代器 end1:容器1结束迭代器 beg1:容器2开始迭代器 end1:容器2结束迭代器 dest:目标容器开始迭代器
-
代码
#include<iostream> #include<vector> #include<algorithm> using namespace std; /* set_union(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest); beg1:容器1开始迭代器 end1:容器1结束迭代器 beg1:容器2开始迭代器 end1:容器2结束迭代器 dest:目标容器开始迭代器 */ class myPrint { public: void operator()(int val) { cout << val << endl; } }; void test1() { vector<int> v1; v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.push_back(5); v1.push_back(6); vector<int> v2; v2.push_back(4); v2.push_back(5); v2.push_back(6); v2.push_back(7); v2.push_back(8); v2.push_back(9); vector<int> vTarget; vTarget.resize(v1.size()+v2.size()); //返回并集最后一个迭代器位置 vector<int>::iterator itEnd = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin()); for_each(vTarget.begin(), itEnd, myPrint());//1 2 3 4 5 6 7 8 9 } int main() { test1(); system("pause"); return 0; }
8.6.3 set_difference(求差集的两个容器必须是有序序列)
- 功能:求两个容器的差集,返回目标容器最后一个含元素的迭代器位置
- 函数原型
set_difference(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
beg1:容器1开始迭代器
end1:容器1结束迭代器
beg1:容器2开始迭代器
end1:容器2结束迭代器
dest:目标容器开始迭代器
- 代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
/*
set_difference(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
beg1:容器1开始迭代器
end1:容器1结束迭代器
beg1:容器2开始迭代器
end1:容器2结束迭代器
dest:目标容器开始迭代器
*/
class myPrint
{
public:
void operator()(int val)
{
cout << val << endl;
}
};
void test1()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
v1.push_back(6);
vector<int> v2;
v2.push_back(4);
v2.push_back(5);
v2.push_back(6);
v2.push_back(7);
v2.push_back(8);
v2.push_back(9);
vector<int> vTarget;
vTarget.resize(max(v1.size(), v2.size()));
//v1和v2的差集
//返回差集最后一个迭代器位置
vector<int>::iterator itEnd1 = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
cout << "v1和v2的差集" << endl;
for_each(vTarget.begin(), itEnd1, myPrint());//1 2 3
//v2和v1的差集
//返回差集最后一个迭代器位置
vector<int>::iterator itEnd2 = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget.begin());
cout << "v2和v1的差集" << endl;
for_each(vTarget.begin(), itEnd2, myPrint());//7 8 9
}
int main()
{
test1();
system("pause");
return 0;
}