The best C++ Nodes
C++语句
- C++头文件取消扩展名h并加上前缀c
#include <iostream>
#include <cmath>
- 名称空间编译指令:
1.using namespace std;
2.std::cout<<std::endl;
3.using std::cout;
using std::cin;
using std::endl;
- C++中可以连续使用赋值运算符
a=b=c=1;
- 使用
const
替代#define
- 进制转换:
十进制:0~9
八进制:0~7
十六进制:0~9+a~f(10~15)
十进制:dex
八进制:oct
十六进制:hex
cout<<hex;
:
:
//都为十六进制
cout<<dec;
:
:
//都为十进制
cout<<oct;
:
:
//都为八进制g
- 后缀类型:
L:long
UL:unsigned long
LL:long long
ULL:unsigned long long
f:float
不加后缀的浮点数视作double
型 cout.put
—>putchar()
(显示一个字符)\b
:退格- 强制类型转换:
①(long)core
②long(core)
③static_cast<long>(core)
- auto声明:
auto n=100;//n is int
auto x=1.5;//n is double
- 长度计算函数:
sizeof()
:计算整个数组长度
strlen()
:计算字符串长度(空字符不计入)
sizeof(数组)>=strlen(数组)+1 - 成员类函数:
getline()
和get()
cin
:每次读取一个字符(char类型)/每次读取一个单词(char [] 类型)
cin.getline()
:每次读取一行,到达换行符并丢弃
cin.get()
: 每次读取一行,到达换行符并保留
int arr[20];
cin.getline(arr,20);
cin.get(arr,20); //返回true或false
//第一个参数:数组名称
//第二个参数:字符数(若参数为20,则最多读取19个)
cin.get(); //返回int或EOF
//无参数
cin.get(无参数)
:读取下一个字符<包括空格和换行符>(处理“/n”)->getchar()
string类
- #include <.string.> + using 编译指令
string str1=“Hello JZ!”;//自动处理大小
string str2;
cout<<str1[1];
cin>>str2;//读取单词
数组
复制:strcpy(arr1,arr2)
连接:strcat(arr1,arr2)
string
复制:str1=str2
连接:使用‘+’合并,使用‘+=’附加到末尾
string str1=“JZ”;
string str2=“Hello!”;
string str3;
str3=str1+str2;//str3:JZHello!
str2+=str1;//str2:Hello!JZ
- 确定字符数:
数组:int len1=strlen(arr1);
string:int len2=arr1.size();
//arr1–>sting对象
//.size()—>string类的一个方法 - 读取字符串:
string:
cin>>arr1;
//读取第一个单词
getline(cin,arr1);
//读取一行
数组:
char arr2[20];
cin.getline(ch,20);
//最多读取19个 - 原始字符串:字符就表示自己
cout<<
R”(Hello!\n”JZ”!
)”;
//Hello!\n”JZ”!
结构
struct inflatable
{
char name[20];
float volume;
double price;
};
C++允许声明结构变量时省略关键词struct
struct inflatable name1;
inflatable name1;
- 结构初始化:
inflatable guest=
{
“ABC”,
1.88,
29.99
};
2.inflatable guest={“ABC”,1.88,29.99};
- 结构中使用string类:
#include <string>
struct inflatable
{
std::string name;
float volume;
double price;
};
- 定义结构的同时创建变量:
struct perks
{
int number;
char car[12];
}name1,name2;
- 同类型结构之间可以赋值
name1=name2;
- 结构数组:
inflatable gifts[100];
cin>>gifts[0].volume;
inflatable gifts[2]=
{
{“Bambi”,0.5,21.99},
{“God”,2000,569}
};
- 共用体
union
:
只能存储int
,long
,double
中的一个
union oneall
{
int a;
long b;
double c;
}idea;
点击查看实例代码
struct widget
{
char brand[20];
int type;
union id
{
long id_num;
char id_char[20];
}id_val;
};
widget price;
if(price.type==1)
cin>>price.id_val.id_num;
else
cin>>price.id_val.id_char;
枚举
enum color{red=1,yellow=2,blue=3};
enum week{Su,Mo,To,We,Th,Fr,Sa};
———————0-—1—2—3-—4—5—6
enum只能使用赋值运算符
new运算符
- 为一个数据对象获得并指定分配内存
int* pt=new int;
*pt=1001;
- new分配的内存块:堆或自由存储区
常规变量分配的内存块:栈 - 使用
delete
释放内存:
int* ps=new int;
*ps=10;
delete ps;
①释放ps指向的内存,但不会删除指针本身
②不能使用delete来释放不是new分配的内存
③对空指针应用delete是安全的
④释放指针不能使该指针的值变为NULL
- 使用new创建动态数组:
使用new[]位数组分配内存,使用delete[]释放
int* pt=new int [10];
delete [] pt;
//pt是指向第一个元素的地址,&pt是整个数组的地址
点击查看实例代码
int* pt;
pt=new char[strlen(animal)+1];
delete [] pt;
- 使用new创建动态结构:
struct things
{
int number;
double price;
};
things* pt=new things;
pt->number=1;
pt->price=99.99;
delete pt;
- 使用new创建字符串数组:
char* str=new char[10+1];
str[10]=‘\0’;
for(int i=0;i<10;i++)
cin>>str[i];
delete [] str;
点击查看实例代码
//定义getname()函数:
char* getname(void)
{
char temp[80];
cin>>temp;
char* pt=new char[strlen(temp)+1];
strcpy(pt,temp);
return pt;
}
int main()
{
char* name;
name=getname();
cout<<name;
delete [] name;
}
- 使用new初始化:
int* p=new int(6);
double* pt=new double(1.2);
struct name{int x;double y;string n;};
name* p=new name{1,2.3,”dwad”};
int* arr=new int[4] {1,3,5,7};
模板类vector
和array
- 模板类
vector
:new创建动态数组的替代品
vector<double>name1(n);
//name1存储n个double类型元素
①包含头文件#include <vector>
②包含在名称空间std
中
③n可以为常量或变量
④无法初始化 - 模板类
array
:
array<double,5>name2;
//name2存储n个double类型元素
①包含头文件#include <array>
②包含在名称空间std
中
③n只能为常量
array<double,3>*pt;
(*pt)[1]=3.5;
(*pt)[2]=4.2;
(*pt)[3]=1.3;
循环和关系表达式
- 前缀格式效率高于后缀格式
++n
>n++
- 基于范围的for循环:用于数组类
遍历所有元素并执行相同操作
①double price[5]={1.2,3.4,5.6,7.8,9.2};
for(double x : price)//原数组的值不变
{
x+=1;
cout<<x<<“ “;
}
②double price[5]={1.2,3.4,5.6,7.8,9.2};
for(double& x : price)//改变原数组的值
{
x+=1;
cout<<x<<“ “;
}
- 成员函数
fail()
和eof()
判读文件结尾:
检测到EOF时,cin.fail()
和cin.eof()
返回true
,否则返回false
while(cin.fail()==false)<===>while(cin.get(ch))
逻辑表达式
- 运算符:
&&
:全真才真,有假即假
||
:有真即真,全假才假
&&
优先级高于||
clear()
方法:
重制错误标记,同时重制文件结尾(EOF)
if(!cin)//输入‘q’结束输入
{
cin.clear();//重制错误
cin.get();//read ‘q’
}
cin.get();//读取换行符
cin.get();//等待输入
while(!(cin>>golf[i]))
{
cin.clear();
while(cin.get()!=‘\n’)
continue;
cout<<“Enter again!”;
}
cctype头文件
const
函数指针
- 获取函数的地址:
函数地址=函数名
think()
是函数,think
是函数地址
process(think);//传递think()地址,使得process()函数能在内部调用think()
process(think());//传递think()返回值
- 声明函数指针:
函数原型:double think(int);
//think是函数
函数指针:double (*pt)(int);
//(*pt)是函数
赋值:pt=think;
//pt就是函数指针 - 使用指针调用函数:
double think(int);
double (*pt)(int);
pt=think;
double x=think(1);
double y=(*pt)(2);
double z=pt(2);
- 自动推断:
函数原型:const double* f1(const double arr[],int n);
函数指针:const double* (*p1)(const double *,int)=f1;
自动推断:auto p1=f1;
- 函数指针数组:
const double* (*pa[3])(const double *,int)={f1,f2,f3};
//pa是一个包含3个函数指针的数组
auto pb=pa;//pa->&pa[0]
const double* (**pb)(const double *,int)=pa;
const double* px=pa[0](av,3);
const double* py=(*pb[1])(av,3);
double x=*pa[0](av,3);
double y=*(*pb[1])(av,3);
点击查看实例代码
#include <iostream>
const double* f1(const double ar[],int n);
const double* f2(const doubel [],int);
const double* f3(const double *,int);
int main()
{
using namespace std;
double av[3]={1112.3,1542.6,2227.9};
const double* (*p1)(const double *,int)=f1;
auto p2=f2;
auto p3=f3;
cout<<(*p1)(av,3)<<“:”<<*(*p1)(av,3)<<endl;
cout<<p2(av,3)<<“:”<<*p2(av,3)<<endl;
cout<<p3(av,3)<<“:“<<*p3(av,3)<<endl;
const double* (*pa[3])(const double *,int)={f1,f2,f3};
for(int i=0;i<3;i++)
cout<<pa[i](av,3)<<“:”<<*pa[i](av,3)<<endl;
const double* (*(*pd)[3])(const double *,int)=&pa;
for(int i=0;i<3;i++)
cout<<(*(*pd)[i])(av,3)<<“:”<<*(*(*pd)[i])(av,3)<<endl;
auto pb=pa;
for(int i=0;i<3;i++)
cout<<pb[i](av,3)<<“:”<<*pb[i](av,3)<<endl;
auto pc=&pa;
for(int i=0;i<3;i++)
cout<<(*pc)[i](av,3)<<“:”<<*(*pc)[i](av,3)<<endl;
const double* pdb=(*pd)[0](av,3);
cout<<pdb<<“:”<<*pdb<<endl;
return 0;
}
const double* f1(const double* ar,int n)
return ar;
const double* f2(const double ar[],int n)
return ar+1;
const double* f3(const double ar[],int n)
return ar+2;
/*
编译结果:
0x16340 : 1112.3
0x16348 : 1542.6
0x16350 : 2227.9
*/
- 使用
typedef
进行简化:
typedef const double* (*p_fun)(const double*,int);
p_fun p1=f1;
p_fun pa[3]={f1,f2,f3};
p_fun (*pd)[3]=&pa;
内联函数
- 常规函数:来回跳跃并记录跳跃位置
- 内联函数:使用相应的函数代码替代函数调用(速度快,占用更多内存)
①代码执行时间短,函数经常被调用(内联函数节省大部分时间)
②在函数声明和定义前加上关键词inline
③一般省略原型,将整个定义放在原型处
④内联函数不能递归
#include <iostream>
inline double square(double x)
{
return x*x;
}
int main()
{
···
}
引用变量
①主要用作函数的形参
②必须在声明引用时初始化(不能先声明再赋值)
int rats;
int& rodents=rats;//地址相同,值相同
void swapr(int& a,int& b);//无须解引用
函数重载与模板
- 默认参数:当函数调用中省略了实参时自动使用的一个值
通过函数原型,从左到右添加默认值,实参按从左到右的顺序依次被赋给形参
int sum(int a=1,int b=2,int c=3);//vaild
int sum(int a,int b=2,int c=3);//vaild
int sum(int a=1,int b,int c=3);//invalid
int beep(int n,int m=2,int j=3);
beep(3);//beep(3,2,3)
beep(3,1);//beep(3,1,3)
beep( ,3);//invalid
- 函数重载:使用多个同名函数
🌟函数特征标不同
函数特征标:参数数目、类型、顺序相关,与变量名、引用、函数返回值类型无关
void sum(char* x);
void sum(const char* x);
void print(const char* str,int width);
void print(double d,int width);
void print(long l,int width);
void print(int i,int width);
void print(const char* str);
double cube(double x);//invalid
double cube(double& x);//invalid
long gronk(int n,float m);//invalid
double gronk(int n,float m);//invalid
- 函数模板:将同一种算法用于不同类型的函数
①将类型作为参数传递给模板
②函数模版不能缩短可执行程序
③一般将模板放在头文件中
template <class T>//class可以用typename替代
void Swap(T& a,T& b)
{
T temp;
temp=a;
a=b;
b=temp;
}
- 重载的模板:并非所有类型都使用相同的算法
被重载的模板的函数特征标必须不同
template <class T>
void Swap(T& a,T& b);
template <class T>
void Swap(T* a,T* b,int n);
- 模板的局限性:
template <class T>
void f(T a,T b)
{
···
}
a=b;//若T为数组,则不成立
if(a>b);//若T为结构,则不成立
- 显示具体化:提供一个具体化函数定义
当编译器找到与函数调用匹配的具体化定义时,将使用该定义,而不是再寻找模板
①非模板函数:
void Swap(int &,int &);
②模板函数:
template <class T>
void Swap(T &,T &);
③具体化的原型:
template <> void Swap<int>(int &,int &);
或
template <> void Swap(int &,int &);
优先级:非模板函数>显示具体化>模板函数
点击查看代码
#include <iostream>
#include <string>
class Person
{
public:
std::string m_name;
int m_years;
Person(std::string name="none", int years=0);
};
Person::Person(std::string name,int years)
{
m_name = name;
m_years = years;
}
template <class T>
bool Compare(T& a, T& b)
{
if (a == b)
{
return true;
}
else
{
return false;
}
}
//具体化(优于常规模板)
template<> bool Compare(Person& p1, Person& p2)
{
if (p1.m_name == p2.m_name && p1.m_years == p2.m_years)
{
return true;
}
else
{
return false;
}
}
int main()
{
Person p1("Tom", 10);
Person p2("Tom", 10);
bool result = Compare(p1, p2);
if (result)
{
std::cout << "p1==p2" << std::endl;
}
else
{
std::cout << "p1!=p2" << std::endl;
}
return 0;
}
- 实例化和具体化:
隐式实例化:编译器使用模板为特定类型生成函数定义
显示实例化:直接命令编译器创建特定的实例
template void Swap<int>(int,int);
//使用Swap()模板生成int类型的函数定义
点击查看实例化代码
template <class T>
T Add(T a,T b)
return a+b;
int m=6;
double x=10.2;
cout<<Add <double> (x,m)<<endl;//强制类型转换
显示具体化:
template <> void Swap<int>(int &,int &);
template <> void Swap(int &,int &);
//不使用Swap()模板,使用专门为int类型显式地定义的函数定义
- 关键字
decltype
:类型转换
decltype(x) y;//使y与x相同类型
decltype(x+y) sum=x+y;//使sum与x+y的类型相同
template <class T1,class T2>
void ft(T1 x,T2 y)
decltype(x+y) sum=x+y;
————————————————————————————————
const double* pd;
decltype(pd) a;//a->const double *
————————————————————————————————
long sum(int);
decltype(sum(3)) b;//b->long
————————————————————————————————
double x=4.4;
decltype(x) a=x;//a->double
decltype((x)) a=x;//a->double &
typedef
与decltype
相结合:
template <class T1,class T2>
void ft(T1 x,T2 y)
{
typedef decltype(x+y) xytype;
xytype xpy=x+y;
xytype arr[10];
xytype& rxy=arr[2];
}
- 后置返回类型:
template <class T1,class T2>
??? gt(T1 x,T2 y)
{
···
return x+y;
}
不能将返回值类型设置为decltype(x+y)
因为此时还未声明x和y的类型
double h(int x,float y);
auto h(int x,float y)->double;//->double(后置返回类型)
auto h(int x,float y)->double
{
···
}
template <class T1,class T2>
auto gt(T1 x,T2 y)->decltype(x+y)
{
···
return x+y;
}
类模板
①用模板类代替普通类
②用模板函数代替成员函数
③类头和所有函数头都以相同的模板声明打头
④类内限定符:将所有Stack改为Stack< Type >
⑤类内定义可以省略模板前缀和类限定符
⑥将所有模板(包括模板类和模板函数)放在一个头文件中
头文件代码
#ifndef WORK_H_
#define WORK_H_
template <class T>
class Stack
{
private:
enum{MAX=10};
T items[MAX];
int top;
public:
Stack()//类内定义
{
top=0;
}
bool isempty();
bool isfull();
bool push(const T& item);
bool pop(T& item);
};
//使用模板成员函数
//template <class T>
// Stack<T>::Stack()
// {
// top=0;
// }
template <class T>
bool Stack<T>::isempty()
{
return top==0;
}
template <class T>
bool Stack<T>::isfull()
{
return top==MAX;
}
template <class T>
bool Stack<T>::push(const T& item)
{
if(top<MAX)
{
items[top++]=item;
return true;
}
else
return false;
}
template <class T>
bool Stack<T>::pop(T& item)
{
if(top>0)
{
item=items[--top];
return true;
}
else
return false;
}
#endif
源文件代码
#include <iostream>
#include <string>
#include <cctype>
#include "work.h"
using std::cout;
using std::cin;
int main()
{
Stack<std::string> st;
char ch;
std::string po;
cout<<"Please enter A to add a purchase order,\n"
<<"P to process a PO,or Q to quit.\n";
while(cin>>ch&&std::toupper(ch)!='Q')
{
while(cin.get()!='\n')
continue;
if(!std::isalpha(ch))
{
cout<<'\a';
continue;
}
switch(ch)
{
case 'A':
case 'a':
cout<<"Enter a PO number to add: ";
cin>>po;
if(st.isfull())
cout<<"stack already full\n";
else
st.push(po);
break;
case 'P':
case 'p':
if(st.isempty())
cout<<"stack already empty\n";
else
{
st.pop(po);
cout<<"PO #"<<po<<" popped\n";
break;
}
}
cout<<"Please enter A to add a purchase order,\n"
<<"P to process a PO,or Q to quit.\n";
}
cout<<"Bye\n";
return 0;
}
- 带参模板:
template <class T,int n>
①模板代码不能修改参数的值,不能使用参数的地址
②实例化模板时,表达式参数的值必须是常量
③类模板只能用显示指定类型方式
④类模板中的参数列表可以有默认参数
点击查看代码
#ifndef ArrayTp_h_
#define ArrayTp_h_
#include <iostream>
#include <cstdlib>
template<class T,int n>
class ArrayTp
{
private:
T ar[n];
public:
ArrayTp() {};
explicit ArrayTp(const T& v);
virtual T& operator[](int i);
virtual T operator[](int i)const;
};
template<class T,int n>
ArrayTp<T, n>::ArrayTp(const T& v)
{
for (int i = 0; i < n; i++)
ar[i] = v;
}
template <class T,int n>
T& ArrayTp<T, n>::operator[](int i)
{
if (i < 0 || i >= n)
{
std::cerr << "Error in array limits: " << i
<< "is out of range\n";
std::exit(EXIT_FAILURE);
}
return ar[i];
}
template <class T,int n>
T ArrayTp<T, n>::operator[](int i)const
{
if (i < 0 || i >= n)
{
std::cerr << "Error in array limits: " << i
<< "is out of range\n";
std::exit(EXIT_FAILURE);
}
return ar[i];
}
#endif // !STUDENT_H_
点击查看代码
#include <iostream>
#include "ArrayTp.h"
int main() {
ArrayTp<int, 5> arr;
for (int i = 0; i < 5; i++)
{
arr[i] = i * 10; // 使用非常量版本的下标运算符重载函数来赋值
}
for (int i = 0; i < 5; i++)
{
std::cout << arr[i] << " "; // 使用常量版本的下标运算符重载函数来访问元素值
}
return 0;
}
例2代码
#include <iostream>
#include <string>
template <class NameT,class AgeT = int>//参数列表可以有默认参数
class Person
{
public:
AgeT m_Age;
NameT m_Name;
Person(NameT name = "none", AgeT age = 0);
};
template <class NameT, class AgeT>
Person<NameT, AgeT>::Person(NameT name, AgeT age)
{
m_Age = age;
m_Name = name;
}
int main()
{
Person<std::string, int> p1("Tom", 3);//类模板只能用显示指定类型方式
Person<std::string> p1("Tom", 3);//使用默认参数int
std::cout << p1.m_Name << " : " << p1.m_Age << std::endl;
return 0;
}
- 类模板对象做函数参数:
1.指定传入的类型
2.参数模板化
3.整个类模板化
点击查看代码
#include <iostream>
#include <string>
template <class NameT, class AgeT = int>
class Person
{
public:
AgeT m_Age;
NameT m_Name;
Person(NameT name = "none", AgeT age = 0);
void show();
};
template <class NameT, class AgeT>
Person<NameT, AgeT>::Person(NameT name, AgeT age)
{
m_Age = age;
m_Name = name;
}
template <class NameT, class AgeT>
void Person<NameT, AgeT>::show()
{
std::cout << "name = " << m_Name << " age = " << m_Age << std::endl;
}
//1.指定传入的类型(常用)
void printPerson1(Person<std::string, int>& p)
{
p.show();
}
//2.参数模板化
template <class NameT, class AgeT>
void printPerson2(Person<NameT, AgeT>& p)
{
p.show();
}
//3.整个类模板化
template <class T>
void printPerson3(T& p)
{
p.show();
}
int main()
{
Person<std::string, int> p1("Tom", 3);
printPerson1(p1);
printPerson2(p1);
printPerson3(p1);
return 0;
}
- 类模板与继承:
①普通类继承类模板
②类模板继承类模板
点击查看代码
#include <iostream>
#include <string>
template <class T>
class Base
{
public:
T m_Age;
Base()
{
m_Age = 0;
}
Base(T Age)
{
m_Age = Age;
}
};
//普通类继承类模板
class Son1 :public Base<int>//必须指定父类中T的类型
{
public:
std::string m_name;
Son1(std::string name,int age)
{
m_name = name;
m_Age = age;
}
};
//类模板继承类模板(更灵活)
template <class T1,class T2>//T1为子类提供,T2为父类提供
class Son2 :public Base<T2>
{
public:
T1 m_name;
Son2(T1 name, T2 age) :Base<T2>(age)
{
m_name = name;
//m_Age = age;//无法直接访问m_Age,因为它的类型取决于T2的类型
}
};
int main()
{
Base<int> b1(20);
std::cout << b1.m_Age << std::endl;
Son1 s1("Tom",22);
std::cout << s1.m_name << " " << s1.m_Age << std::endl;
Son2<std::string, int> s2("Tom", 25);
std::cout << s2.m_name << " " << s2.m_Age << std::endl;
return 0;
}
- 类模板分文件编写:
将类模板的声明和实现一起写到.hpp文件中
person.hpp代码
#pragma once
#include <iostream>
#include <string>
template <class T1,class T2>
class Person
{
private:
T1 m_name;
T2 m_age;
public:
Person(T1 name, T2 age);
void show();
};
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>::show()
{
std::cout << "name = " << m_name << " age = " << m_age << std::endl;
}
work.cpp代码
#include <iostream>
#include "person.hpp"
int main()
{
Person<std::string, int> p1("Tom", 10);
p1.show();
return 0;
}
- 类模板与友元:
直接在类内声明友元最方便
点击查看代码
#include <iostream>
#include <string>
template <class T1, class T2>
class Person
{
private:
T1 m_name;
T2 m_age;
public:
Person(T1 name, T2 age);
void show();
//友元函数
friend void showPerson(Person& p)
{
p.show();//直接在类内声明
}
};
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>::show()
{
std::cout << "name = " << m_name << " age = " << m_age << std::endl;
}
int main()
{
Person<std::string, int> p1("Tom", 10);
showPerson(p1);
return 0;
}
- 模板别名:
①使用typedef
typedef std::array<double,12> arrd;
arrd days;
typedef std::array<int,12> arri;
arri hours;
②使用using=
template<class T>//写在main函数外面
using arrtype=std::array<T,12>;
arrtype<double> arrd;
arrtype<int> arri;
using arrtype=std::array<double,12>;
arrtype arrd;
用于非模板时:两者等价
typedef const char* pc;
using pc=const char*;
typedef const int*(*px)[10];
using px=const int*(*)[10];
存储特性
- 单独编译:
①头文件:函数原型、const定义的常量、结构声明、类声明、模板声明、内联函数
②源文件:函数定义
③源文件:函数调用
包含自己头文件时使用引号而不是尖括号
”coodin.h”
<coodin.h>
- ifndef和pragma once:
防止一个源文件两次包含同一个头文件
#ifndef 标识
#define 标识
···
···
#endif
#pragma once
···
···
①标识可以自由命名但必须唯一
②命名规则:头文件全名大写,前后加下划线
stdio.h
—>_STDIO_H_
点击查看代码
#ifndef _MACH_H_
#define _MACH_H_
···
···
#endif
- 静态变量:
默认情况下,静态变量、数组和结构的每个元素值都为0
int a;//可以在程序其他文件中使用(a默认初始化为0)
static int b=200;//只能在此文件全局使用
int main()
{
···
}
void fun(int n)
{
static int c=300;//只能在fun函数中使用
}
- 外部变量声明:
①定义声明
②引用声明:使用关键字extern
且不能进行初始化
①:
int x;
②:
extern int x;
在多文件中使用外部变量:
①在一个文件中定义变量
②使用该变量的其他文件必须使用extern声明它
//file1.cpp
int a=1;
extern int b=2;//此处可省略extern
//file2.cpp
extern int a;
extern int b;
···//use a and b from file1.cpp
作用域解析运算符( :: )
放在变量名前,表示使用变量的全局版本
目的:清晰和避免错误
#include <iostream>
using namespace std;
int x;
void sum()
{
::x+=10;
return ::x;
}
int main()
{
cout<<sum();
}
- 静态变量声明:
使用关键字static
作用:只能在其所属的文件中使用
#include <iostream>
static int a=10;
int main()
{
using namespace std;
a=a+1;
}
在函数中使用static:静态局部变量只进行一次初始化,并且 值保持不变
void count(const char* str)
{
using namespace std;
static int total=0;
int count=0;
while(*str++)
count++;
total+=count;
cout<<count<<endl;
cout<<total<<endl;
}
count(“abc”);//3 3
count(“def”);//3 6
- const:
const全局变量的链接性为内部的,使用const就像使用了static
const int fingers=10;//same as static const int fingers=10
int main()
{
···
}
- 函数和链接性:
①默认下,函数的链接性为外部的,即可以在文件间共享
②使用static
将函数链接性设置为内部的,即只能在一个文件中使用
必须同时在原型和函数定义中使用关键字
static int private(double x);
···
static int private(double x);
{
···
}
名称空间
- 名称空间的定义:
#include <iostream>
using namespace std;
namespace A
{
int a=100;
}
namespace B
{
int a=200;
}
void text()
{
cout<<“A中a=”<<A::a;//100
cout<<“B中a=”<<B::a;//200
}
- 命名空间只能在全局范围定义:
//局内定义命名空间是错误的
void text()
{
namespace A//invalid
{
int a=100;
}
}
- 命名空间可以嵌套:
namespace A
{
int a=100;
namespace B
{
int a=200;
}
}
void text()
{
cout<<“A中的a=”<<A::a;//100
cout<<“B中的a=”<<A::B::a;//200
}
- 命名空间是开放的:可以随时加入新成员到已有的命名空间中
namespace A
{
int a=100;
int b=200;
}
namespace A
{
int c=300;
}
- 命名空间可以存放变量和函数:
namespace A
{
int a=100;//变量
void fun()//函数
{
cout<<“a=”<<a<<endl;
}
}
void text()
{
cout<<“A中的a=”<<A::a<<endl;
A::fun();
}
- 命名空间中的函数可以在命名空间外定义:
namespace A
{
int a=100;
void fun()
}
void A::fun()
{
cout<<“a=”<<a<<endl;
}
void text()
{
cout<<“A中的a=”<<A::a<<endl;
A::fun();
}
- 无命名空间:只能在本文件内访问,相当于加了static
namespace
{
int a=10;
void fun()
{
cout<<“Hello”<<endl;
}
}
//只能在当前文件直接访问a和fun()
void text()
{
cout<<“a=”<<a<<endl;
fun();
}
对象和类
- 类的定义:定义这个类的属性和方法声明
class 类名
{
private:
//私有的行为或属性
public:
//公共的行为或属性
};
class Point
{
private:
int xPos;//类成员不能初始化
int yPos;
public:
void setPoint(int x,int y);
void printfPoint();
};
- 类的实现:
①在类定义时完成对成员函数的定义
②在类定义外部进行完成
#include <iostream>
using namespace std;
class Point
{
private:
int xPos;
int yPos;
public
void setPoint(int x,int y)
{
xPos=x;
yPos=y;
}
void printPoint()
{
cout<<“x=”<<xPos<<endl;
cout<<“y=”<<yPos<<endl;
}
};
int main()
{
Point M;
M.setPoint(10,20);
M.printPoint();
return 0;
}
#include <iostream>
using namespace std;
class Point
{
private:
int xPos;
int yPos;
public:
void setPoint(int x,int y);
void printPoint();
};
void Point::setPoint(int x,int y)//通过作用域操作符‘::’实现函数
{
xPos=x;
yPos=y;
}
void Point::printPoint()
{
cout<<“x=”<<xPos<<endl;
cout<<“y=”<<yPos<<endl;
}
int main()
{
Point M;
M.setPoint(10,20);
M.printPoint();
return 0;
}
const
成员函数:保证函数不会修改调用对象
只要类方法不修改调用对象,就应将其声明为const
void show() const;
void Stock::show() const
{
···
}
- 构造函数:在创建对象时初始化对象的数据成员(无须用户显示调用)
特点:
①构造函数名与类名相同
②无返回值
③自动调用
④只能调用一次
⑤可以重载
类型:
①无参数构造函数
②一般构造函数
③复制构造函数
class Complex
{
private:
double m_x;//一般在数据成员名中使用m_前缀
double m_y;
public:
//无参构造函数
//如果类中没有构造函数,则默认生成无参构造函数
Complex(void)
{
m_x=0.0;
m_y=0.0;
}
//一般构造函数
//一个类可以有多个一般构造函数形成函数重载
Complex(double x,double y)
{
m_x=x;
m_y=y;
}
//复制构造函数
//根据一个已知对象复制出一个新的对象
//如果类中没有复制构造函数,则默认创建一个
//当类中有指针成员时,由系统默认创建的复制构造函数存在风险
Complex(const Complex& p1)
{
m_x=p1.m_x;
m_y=p1.m_y;
}
};
//显示法调用构造函数:
Complex p1=Complex(1.2,3.4);//调用一般构造函数
Complex p1=Complex();//调用无参构造函数
Complex p1=Complex(p2);//调用复制函数
//隐式法调用构造函数:
Complex p1(1.2,3.4);//调用一般构造函数
Complex p1={1.2,3.4}; //调用一般构造函数
Complex p1=p2; 调用复制函数
- 初始化列表:
能使用初始化列表尽量使用初始化列表
①只能用于构造函数
②初始化顺序必须与在类中声明顺序相同
③必须用这种格式初始化非静态const成员
,引用成员
,常量成员
,没有默认构造函数的类
(不必调用默认构造函数来初始化,而是直接调用拷贝构造函数)
点击查看代码
#include <iostream>
class Person
{
private:
const int m_num;//must use it!
int& m_x; //must use it!
int m_y; //not necessary but can use it
int m_z; //not necessary but can use it
public:
//Person();//invalid
Person(int num,int x);
Person(int num, int x, int y, int z);
~Person();
friend std::ostream& operator<<(std::ostream& os, const Person& p);
};
Person::Person(int num, int x) :m_num(num), m_x(x), m_y(0), m_z(0) { }
//Person::Person(int num, int x) :m_num(num), m_x(x)//valid
//{
// m_y = 0;
// m_z = 0;
//}
Person::Person(int num, int x, int y, int z) :m_num(num), m_x(x), m_y(y), m_z(z) { }
//Person::Person(int num, int x, int y, int z) :m_num(num), m_x(x)//valid
//{
// m_y = y;
// m_z = z;
//}
Person::~Person(){}
std::ostream& operator<<(std::ostream& os, const Person& p)
{
os << "num = " << p.m_num << " x = " << p.m_x << " y = " << p.m_y << " z = " << p.m_z;
return os;
}
int main()
{
Person text0(1, 2);
Person text1(1, 2, 3, 4);
std::cout << text0 << std::endl << text1 << std::endl;
return 0;
}
在继承中使用初始化列表:
①构造函数不能继承
②子类不能直接初始化父类成员,必须调用父类的构造函数初始化父类成员
③子类的构造函数的初始化列表可以包含父类的构造函数
,子类成员的初始化
,不能包含父类成员的初始化
点击查看代码
#include <iostream>
class Base
{
protected:
int m_A;
int m_B;
public:
Base();
Base(int x,int y);
};
Base::Base() : m_A(0),m_B(0) {}
Base::Base(int x,int y) : m_A(x),m_B(y) {}
class Son : public Base
{
private:
int m_B;
public:
Son();
Son(const Base& tp, int C);
Son(int A, int B,int C);
void out();
};
Son::Son() : Base(), m_B(0) {}
Son::Son(const Base& tp, int C) :Base(tp), m_B(C){}
Son::Son(int A, int B,int C) : Base(A,B), m_B(C) {}
//Son::Son() : m_A(0),Base::m_B(0), m_B(0) {}//invalid
void Son::out()
{
std::cout << "Base::m_A = " << m_A << " ";
std::cout << "Base::m_B = " << Base::m_B << " ";
std::cout << "Son::m_B = " << m_B << std::endl;
}
int main()
{
Son s(15, 25, 35);
Son z(Base(1, 2), 3);
Son x;
s.out();
z.out();
x.out();
return 0;
}
- 析构函数:在对象销毁时自动调用
特点:
①析构函数只能有一个,不能重载
②析构函数不能有参数
③如果没有析构函数,则默认生成无参析构函数
④在return语句之前执行
⑤delete会触发析构函数但free不行
class Cperson
{
private:
int* pp;
public:
Cperson()
{
pp=new int;
cout<<“Beginning”<<endl;
}
~Cperson()
{
delete pp;
cout<<“End”<<endl;
}
};
int main()
{
Cperson();
system(“pause”);
return 0;
}
- new和delete:
①new和delete必须相互兼容,new对应delete,new[]对应delete[]
②多个构造函数必须以相同方式使用new,要么都带[],要么都不带,因为只有一个析构函数 this
指针:指向被调用的成员函数所属的对象
用途:
①形参与成员变量同名时,可以this
指针来区分
②在类的非静态成员函数中可以返回对象本身
✨当你进入一个房子后,你可以看见桌子、椅子等,但是房子的全貌 ,你看不到了。对于一个对象来说,你可以看到它的成员变量,但是看不到对象本身了。所以有了this指针,它时时刻刻指向你这个对象本身。
class person
{
public:
int age;
person(int age)
{
//age=age
this->age=age;
}
person& personAdd(person& p)
{
this->age+=p.age;
return *this;
}
};
int main()
{
person p1(10);
cout<<“p1.age=”<<p1.age<<endl;
person p2(20);
p2.personAdd(p1).personAdd(p1);//20+10+10=40
cout<<“p2.age=”<<p2.age<<endl;
return 0;
}
- 对象数组:每个数组元素都是对象的数组
要创建类对象数组,则这个类必须有默认构造函数
点击查看代码
#include <iostream>
using namespace std;
class exam
{
public:
exam()
{
x=123;
}
exam(int n)
{
x=n;
}
int get_x()
{
return x;
}
private:
int x;
};
int main()
{
exam arr1[4]={11,22,33,44};
exam arr2[4]={55,66};
exam arr3[4];
for(int j=0;j<4;j++)
{
cout<<arr1[j].get_x()<<“ ”;
}//11 22 33 44
cout<<endl;
for(int j=0;j<4;j++)
{
cout<<arr2[j].get_x()<<“ ”;
}//55 66 123 123
cout<<endl;
for(int j=0;j<4;j++)
{
cout<<arr3[j].get_x()<<“ ”;
}//123 123 123 123
cout<<endl;
return 0;
}
点击查看代码
#include <iostream>
#include <cmath>
using namespace std;
class Complex
{
private:
double real;
double imag;
public:
Complex(double r,double i)
{
real=r;
imag=i;
}
Complex()
{
real=0.0;
imag=0.0;
}
~Complex()
{
cout<<“Destructor called.”<<endl;
}
double abscomplex()
{
double t;
t=real*real+imag*imag;
return sqrt(t);
}
};
int main()
{
Complex com[3]=
{
Complex(1.1,2.2),
Complex(3.3,4.4),
Complex(5.5,6.6)
};
cout<<com[0].abscomplex()<<endl;
cout<<com[1].abscomplex()<<endl;
cout<<com[2].abscomplex()<<endl;
return 0;
}
- 在类中声明数组:
①使用static
关键字
②使用枚举
class name
{
private:
const int Months=12;//invalid
static int Months=12;//invalid
static const int Months=12;//valid
double costs[Months];
···
}
class name
{
private:
enum{Months=12};
double costs[Months];
}
- 静态成员变量:使用
static
关键字
①静态成员是整型(或枚举型)const,可以在类声明时初始化
②类内声明,类外初始化
③所以对象共享一份数据
④有访问权限
#include <iostream>
using namespace std;
class Person
{
public:
static int m_A;//不能初始化
//const static int m_A = 10;//可以初始化
private:
static int m_B;
};
int Person::m_A = 10;
int Person::m_B = 10;
int main()
{
Person p1;
p1.m_A = 100;
cout << "p1.m_A = " << p1.m_A << endl;//100
Person p2;
p2.m_A = 200;
//通过对象访问
cout << "p1.m_A = " << p1.m_A << endl;//200
cout << "p2.m_A = " << p2.m_A << endl;//200
//通过类名访问
cout << "m_A = " << Person::m_A << endl;//200
//私有权限无法访问
//cout << "m_B = " << Person::m_B << endl;//invalid
}
- 静态成员函数:
①程序共享一个函数
②静态成员函数只能访问静态成员变量
#include <iostream>
using namespace std;
class Person
{
public:
static int m_A;//不能初始化
int m_B;
static void fun()
{
cout << "fun调用" << endl;
m_A = 100;
//m_B = 100;//invalid不可访问非静态成员
}
private:
static void fun2()
{
cout << "fun2调用" << endl;
}
};
int Person::m_A = 10;
int main()
{
//通过对象访问
Person p1;
p1.fun();
//通过类名访问
Person::fun();
//Person::fun2();//私有权限无法访问
}
- 作用域内枚举:
枚举变量发生冲突:
enum egg{Small,Medium,Large,Jumbo};//invalid
enum t_shirt{Small,Medium,Large,Xlarge};//invalid
使用作用域内枚举:
enum class egg{Small,Medium,Large,Jumbo};
enum class r_shirt{Small,Medium,Large,Xlarge};
友元
- 友元函数: 普通函数可以访问类的私有成员
①定义在类外的普通函数
②不属于任何类
③需要在类定义中加以声明并在前面加上关键字friend
#include <iostream>
using namespace std;
class Student
{
private:
int m_age;
public:
void SetAge(int age);
//需要在前面加`friend`
friend void ShowAge(Student stu);
};
//定义成员函数:
void Student::SetAge(int age)
{
m_age=age;
}
//定义普通函数(不是类的成员函数)
//不加`friend`
void ShowAge(Student stu)
{
cout<<"stu.age: "<<stu.m_age<<endl;
}
int main()
{
Student stu;
stu.SetAge(18);
ShowAge(stu);
return 0;
}
- 友元类:类A中的成员函数可以访问类B中的私有成员
friend class 类名;
类名必须是已经定义的类
#include <iostream>
using namespace std;
class A
{
private:
int m_age;
public:
void SetAge(int age)
{
m_age = age;
}
friend class B;
};
class B
{
public:
void ShowAge(A a)
{
cout << "a.age: " << a.m_age << endl;
}
};
int main()
{
A a;
a.SetAge(666);
B b;
b.ShowAge(a);
return 0;
}
注意:
①友元关系不能被继承
②友元管系是单向的,不具交换性
③友元关系不具有交换性
运算符重载
将两个或多个类声明的对象直接相加减
使用关键字operator
- 方法①:用类的成员函数来实现
Time operator+(const Time& t)const;
Time operator-(const Time& t)const;
Time operator*(double n)const;
Box operator+(const Box& b);
在类中定义:
点击查看代码
#include <iostream>
using namespace std;
class Box
{
private:
double length;
double breadth;
double height;
public:
double getVolume(void)//求体积
return length*breadth*height;
void setLength(double len)//设置长度
length=len;
void setBreadth(double bre)//设置宽度
breadth=bre;
void setHeight(double hei)//设置高度
height=hei;
//重载+运算符,用于把两个Box对象相加
Box operator+(const Box& b)
{
Box box;
box.length=this->length+b.length;
box.breadth=this->breadth+b.breadth;
box.height=this->height+b.height;
return box;
}
};
int main()
{
Box Box1;
Box Box2;
Box Box3;
double volume=0.0;
// Box1 详述
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// Box2 详述
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// Box1 的体积
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume <<endl;
// Box2 的体积
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;
// 把两个对象相加,得到 Box3
Box3 = Box1 + Box2;
// Box3 的体积
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume <<endl;
return 0;
}
在类外定义:
点击查看代码
//mytime1.h
#ifndef MYTIME1_H_
#define MYTIME1_H_
class Time
{
private:
int hour;
int minutes;
public:
Time();
Time(int h,int m=0);
void AddMin(int m);
void AddHr(int h);
void Reset(int h=0,int m=0);
Time operator+(const Time& t)const;
void Show()const;
};
#endif
//mytime1.cpp
#include <iostream>
#include “mytime1.h”
Time::Time()
{
hours=minutes=0;
}
Time::Time(int h,int m)
{
hours=h;
minutes=m;
}
void Time::AddMin(int m)
{
minutes+=m;
hours+=minutes/60;
minutes%=60;
}
void Time::AddHr(int h)
{
hours+=h;
}
void Time::Reset(int h,int m)
{
hours=h;
minutes=m;
}
Time Time::operator+(const Time& t)const
{
Time sum;
sum.minutes=minutes+t.minutes;
sum.hours=hours+t.hours+sum.minutes/60;
sum.minutes%=60;
return sum;
}
void Time::Show()const
{
std::cout<<hours<<“ hours,”<<minutes<<“ minutes”;
}
不可重载运算符:
- 限制🚫:=、()、[]、->运算符只能通过成员函数进行重载,不能通过友元函数进行重载
方法②:通过类的友元函数来实现(友元运算符)
点击查看代码
#include <iostream>
using namespace std;
class Complex
{
private:
int Real, Image;
public:
Complex(float r = 0, float i = 0)
{
Real = r;
Image = i;
}
float GetR()
{
return Real;
}
float GetI()
{
return Image;
}
void Show()
{
cout << Real << " " << Image << endl;
}
friend Complex operator+(Complex&, Complex&);//友元函数
friend Complex operator+(Complex&, float);//友元函数
friend Complex operator-(Complex);//友元函数
void operator+=(Complex&);//成员函数
};
Complex operator+(Complex& c1, Complex& c2)
{
Complex t;
t.Real = c1.Real + c2.Real;
t.Image = c1.Image + c2.Image;
return t;
}
Complex operator+(Complex& c, float s)
{
Complex t;
t.Real = c.Real + s;
t.Image = c.Image;
return t;
}
Complex operator-(Complex c)
{
return Complex(-c.Real, -c.Image);
}
void Complex::operator+=(Complex& c)
{
Real = Real + c.Real;
Image = Image + c.Image;
}
int main()
{
Complex c1(10, 20), c2(20, 30), c3;
c1.Show();
c1 += c2;
c1.Show();
c3 = c1 + c2;
c3.Show();
return 0;
}
成员函数与友元函数实现运算符重载对比:
点击查看代码
//友元函数
friend Complex operator+(Complex&, Complex&);
Complex operator+(Complex& c1, Complex& c2)
{
Complex t;
t.Real = c1.Real + c2.Real;
t.Image = c1.Image + c2.Image;
return t;
}
//成员函数
Complex operator+(Complex&);
Complex operator+(Complex& c)
{
Complex t;
t.Real = Real + c.Real;
t.Image = Image + c.Image;
return t;
}
重载<<运算符:
点击查看代码
//只能通过友元来实现(cout<<···)
friend std::ostream& operator<<(std::ostream& os,const Person& p);
std::ostream& operator<<(std::ostream& os,const Person& p)
{
os << p.hours << "hours, " << p.minutes << " minutes";
return os;//实现链式
}
//通过类成员实现(···<<cout)
std::ostream& operator<<(std::ostream& os);
std::ostream& Person::operator<<(std::ostream& os)
{
os << hours << "hours, " << minutes << " minutes";
return os;//实现链式
}
int main()
{
Person A(1,30);
Person B(3,45);
cout<<A<<B<<endl;
A<<cout<<endl;//通过类成员实现(cout在后)
}
重载>>运算符:
点击查看代码
friend std::istream& operator>>(std::istream& is, String& st);
std::istream& operator>>(std::istream& is, String& st)
{
char temp[80];
is.get(temp, 80);
if (is)
{
//使用赋值运算符重载
//String& String::operator=(const char* s)
st = temp;
}
while (is && is.get() != '\n')
continue;
return is;
}
重载++运算符:
方法①:利用友元函数实现
点击查看代码
#include <iostream>
using namespace std;
class Person
{
friend ostream& operator<<(ostream& os, const Person& p);
friend Person& operator++(Person& p);
friend Person operator++(Person& p, int);
private:
int m_A;
int m_B;
public:
Person()
{
m_A = m_B = 0;
}
Person(int A, int B = 0)
{
m_A = A;
m_B = B;
}
};
ostream& operator<<(ostream& os, const Person& p)
{
os << "A = " << p.m_A << " B = " << p.m_B;
return os;
}
//前置++运算符
Person& operator++(Person& p)
{
p.m_A++;
p.m_B++;
return p;
}
//后置++运算符
Person operator++(Person& p, int)
{
Person temp = p;
p.m_A++;
p.m_B++;
return temp;
}
int main()
{
Person x;
Person a(1, 1);
Person b(10, 10);
cout << a << endl;
cout << ++a << endl;
cout << a++ << endl;
cout << a << endl;
return 0;
}
方法②:利用成员函数实现
点击查看代码
#include <iostream>
using namespace std;
class Person
{
friend ostream& operator<<(ostream& os, const Person& p);
private:
int m_A;
int m_B;
public:
Person()
{
m_A = m_B = 0;
}
Person(int A, int B = 0)
{
m_A = A;
m_B = B;
}
//前置++运算符
Person& operator++()
{
m_A++;
m_B++;
return *this;
}
//后置++运算符
Person operator++(int)
{
Person temp;
temp = *this;
m_A++;
m_B++;
return temp;
}
};
ostream& operator<<(ostream& os, const Person& p)
{
os << "A = " << p.m_A << " B = " << p.m_B;
return os;
}
int main()
{
Person x;
Person a(1, 1);
Person b(10, 10);
cout << a << endl;
cout << ++a << endl;
cout << a++ << endl;
cout << a << endl;
return 0;
}
赋值运算符重载(深拷贝)(2种):
如果类中有属性指向堆区,做赋值操作时会出现深浅拷贝问题
点击查看代码
#include <iostream>
using namespace std;
class Person
{
public:
int* m_num;//传入地址
Person()
{
m_num = new int (0);
}
Person(int num)
{
m_num = new int(num);
}
Person& operator=(Person& p)//等价于*this=p
{
//若this不为空,则先释放this指向的堆
if (m_num != NULL)
{
delete m_num;
m_num = NULL;
}
//浅拷贝(导致堆重复释放从而报错)
// m_num = p.m_num;
//深拷贝(为this创建新空间,避免析构函数重复释放同一个空间)
m_num = new int(*p.m_num);
return *this;
}
~Person()
{
if (m_num != NULL)
{
delete m_num;
m_num = NULL;
}
}
};
int main()
{
Person a;
Person b(20);
Person c(30);
cout << "a = " << *a.m_num << endl;
cout << "b = " << *b.m_num << endl;
cout << "c = " << *c.m_num << endl;
a = b = c;
cout << "a = b = c" << endl;
cout << "a = " << *a.m_num << endl;
cout << "b = " << *b.m_num << endl;
cout << "c = " << *c.m_num << endl;
return 0;
}
点击查看代码
class String
{
private:
char* str;
int len;
public:
//重载
String& operator=(const String&);
String& operator=(const char*);
};
String& String::operator=(const String& st)
{
if (str != NULL)
{
delete[] str;
str = NULL;
}
len = st.len;
str = new char[len + 1];
strcpy(str, st.str);
return *this;
}
String& String::operator=(const char* s)
{
if (str != NULL)
{
delete[] str;
str = NULL;
}
len = strlen(s);
str = new char[len + 1];
strcpy(str, s);
return *this;
}
深度复制和拷贝:
点击查看代码
class StringBad
{
private:
char* str;
int len;
public:
StringBad();
StringBad(const char* s);
//复制构造函数(深度复制)
StringBad(const StringBad& st);
//赋值运算符重载(深拷贝)
StringBad& operator=(const StringBad& st);
~StringBad();
};
StringBad::StringBad(const StringBad& st)
{
len = st.len;
str = new char[len + 1];
strcpy_s(str, len + 1, st.str);
}
StringBad& StringBad::operator=(const StringBad& st)
{
if (str != NULL)
{
delete[] str;
str = NULL;
}
len = st.len;
str = new char[len + 1];
strcpy_s(str, len + 1, st.str);
return *this;
}
int main()
{
StringBad a = ("abc");
StringBad b = a;//既有深度复制也有深拷贝
//等价与StringBad a = StringBad(b);
StringBad c;
c = a;//只有深拷贝
}
关系运算符重载:
点击查看代码
#include <iostream>
using namespace std;
class Person
{
public:
string m_name;
int m_age;
Person()
{
m_name = "none";
m_age = 0;
}
Person(string name, int age)
{
m_name = name;
m_age = age;
}
bool operator==(Person& p)
{
if (m_name == p.m_name && m_age == p.m_age)
return true;
else
return false;
}
};
int main()
{
Person name1("Tom", 18);
Person name2("Tom", 18);
if (name1 == name2)
cout << "相等" << endl;
else
cout << "不相等" << endl;
return 0;
}
重载函数调用运算符:
点击查看代码
#include <iostream>
using namespace std;
class Person
{
public:
//重载的()操作符,也称为仿函数
void operator()(string text)
{
cout << text << endl;
}
int operator()(int a, int b)
{
return a + b;
}
};
int main()
{
Person p;
p("hello!");
int num = p(1, 1);
cout << "num = " << num << endl;
//匿名对象调用
cout << "num = " << Person()(2, 3) << endl;
return 0;
}
重载中括号运算符:
点击查看代码
#include <iostream>
class String
{
private:
int len;
char* str;
public:
String();
String(const char* st);
~String();
char& operator[](int i);
const char& operator[](int i)const;//重载
};
String::String()
{
len = 0;
str = new char[1];
str[0] = '\0';
}
String::String(const char* st)
{
len = std::strlen(st);
str = new char[len + 1];
strcpy_s(str, len + 1, st);
}
String::~String()
{
delete[] str;
}
char& String::operator[](int i)
{
return str[i];
}
//供const String对象使用(重载)
const char& String::operator[](int i)const
{
return str[i];
}
int main()
{
String a("012");
std::cout << a[0] << a[1] << a[2] << std::endl;
a[0] = '9';//可以修改
const String b("012");//只读数据,不能修改
std::cout << b[0] << b[1] << b[2] << std::endl;//(只读数据)
//b[0] = '9';//invalid(不能修改)
return 0;
}
利用构造函数重载运算符:
点击查看代码
#include <iostream>
class Person
{
private:
double m_x;
double m_y;
double Len;
public:
void set_len()
{
Len = sqrt(m_x * m_x + m_y * m_y);
}
Person();
Person(double x, double y);
~Person();
Person operator+(const Person& p);
Person operator-(const Person& p);
Person operator-();
Person operator*(double n)const;
friend std::ostream& operator<<(std::ostream& os, const Person& p);
friend Person operator*(double n, const Person& p);
};
//构造函数:
Person::Person()
{
m_x = m_y = 0;
set_len();
}
Person::Person(double x, double y)
{
m_x = x;
m_y = y;
set_len();
}
//析构函数:
Person::~Person()
{
}
std::ostream& operator<<(std::ostream& os, const Person& p)
{
os << "x = " << p.m_x << " y = " << p.m_y
<< " length = " << p.Len << std::endl;
return os;
}
//不使用构造函数:
//Person Person::operator+(Person& p)
//{
// Person temp;
// temp.m_x = m_x + p.m_x;
// temp.m_y = m_y + p.m_y;
// temp.set_len();//多一步:需要重新计算长度的值
// return temp;
//}
//使用构造函数:
Person Person::operator+(const Person& p)
{
return Person(m_x + p.m_x, m_y + p.m_y);
}
Person Person::operator-(const Person& p)
{
return Person(m_x - p.m_x, m_y - p.m_y);
}
Person Person::operator-()
{
return Person(-m_x, -m_y);
}
Person Person::operator*(double n)const
{
return Person(n * m_x, n * m_y);
}
Person operator*(double n, const Person& p)
{
return p * n;
}
int main()
{
Person a(3, 4);
Person b(6, 8);
std::cout << a << b;
std::cout << "a + b : " << a + b;
std::cout << "b - a : " << b - a;
std::cout << "- a : " << - a;
std::cout << "a * 10 : " << a * 10;
std::cout << "10 * a : " << 10 * a;
return 0;
}
类型转换
- 通过构造函数实现转换:从某种类型到类类型的转换
①只接受一个参数的构造函数
②2个参数但给第二个参数提供默认值
③使用关键字explicit
可以关闭自动类型转换
点击查看代码
#include <iostream>
class Person
{
private:
int m_num1;
double m_num2;
public:
Person();
explicit Person(int num1);//只需要在类声明中加explicit
//Person(int num1, double num2 = 0.0);
~Person();
void show_num()const;
};
Person::Person()
{
m_num1 = m_num2 = 0;
}
Person::Person(int num1)
{
m_num1 = num1;
m_num2 = 0;
}
//Person::Person(int num1, double num2)
//{
// m_num1 = num1;
// m_num2 = num2;
//}
Person::~Person()
{
}
void Person::show_num()const
{
std::cout << "num1 = " << m_num1 << " num2 = " << m_num2 << std::endl;
}
int main()
{
Person a;
//a = 3;//invalid
a = Person(3);
//a=(Person)3;
//a = Person(3,2.2);
a.show_num();
}
- 转换函数:从类类型到某种类型的转换
operator typename();
①转换函数必须是类方法
②转换函数无返回函数
③转换函数无参数
点击查看代码
#include <iostream>
class Person
{
private:
int m_num1;
double m_num2;
public:
Person();
explicit Person(int num1);//只需要在类声明中加explicit
Person(int num1, double num2 = 0.0);
~Person();
void show_num()const;
operator int()const;
operator double()const;
//explicit operator int()const;//只能进行强制类型转换
//explicit operator double()const;//无法进行隐式转换
};
Person::Person()
{
m_num1 = m_num2 = 0;
}
Person::Person(int num1)
{
m_num1 = num1;
m_num2 = 0;
}
Person::Person(int num1, double num2)
{
m_num1 = num1;
m_num2 = num2;
}
Person::~Person()
{
}
void Person::show_num()const
{
std::cout << "num1 = " << m_num1 << " num2 = " << m_num2 << std::endl;
}
Person::operator int()const
{
return int(m_num1);
}
Person::operator double()const
{
return m_num2;
}
int main()
{
Person a;
a = Person(3,2.2);
a.show_num();
int INT = a;
double DOU = a;
//因为有int和double出现二义性,所以无法隐式转换
//std::cout << a;//invalid
std::cout << (int)a << std::endl;
std::cout << (double)a << std::endl;
std::cout << "INT = " << INT << " DOU = " << DOU << std::endl;
return 0;
}
转换函数配合友元函数的实现:
点击查看代码
#include <iostream>
class Person
{
private:
int m_num1;
double m_num2;
public:
Person();
Person(int num1);//只需要在类声明中加explicit
Person(int num1, double num2);
~Person();
void show_num()const;
//operator int()const;//如果2种转换函数同时存在
//operator double()const;//导致隐式转换出现二义性
Person operator+(const Person& p)const;
};
Person::Person()
{
m_num1 = m_num2 = 0;
}
Person::Person(int num1)
{
m_num1 = num1;
m_num2 = 0;
}
Person::Person(int num1, double num2)
{
m_num1 = num1;
m_num2 = num2;
}
Person::~Person()
{
}
void Person::show_num()const
{
std::cout << "num1 = " << m_num1 << " num2 = " << m_num2 << std::endl;
}
//Person::operator int()const
//{
// return int(m_num1);
//}
//Person::operator double()const
//{
// return m_num2;
//}
Person Person::operator+(const Person& p)const
{
return Person(p.m_num1 + m_num1, p.m_num2 + m_num2);
}
int main()
{
Person a,c;
a = Person(3,2.2);
a.show_num();
//显示转换
c = a + Person(4);
c = Person(4) + a;
//隐式转换
c = a + 4;
//c = 4 + a;//invalid(需要定义友元函数实现)
c.show_num();
return 0;
}
继承
- protected:保护属性
①protected修饰的成员不能被外界访问
②protected修饰的成员能被子类直接访问
③protected关键字为继承而生
#include <iostream>
class Person
{
public:
int m_A;
Person();
protected:
int m_B;
private:
int m_C;
};
Person::Person()
{
m_A = 1;
m_B = 2;//类内访问
m_C = 3;
}
int main()
{
Person p;
p.m_A = 10;
//p.m_B = 20;//invalid(不能类外访问)
//p.m_C = 30;//invalid(不能类外访问)
return 0;
}
- 继承:
①减少重复代码
②添加功能
③添加数据
④修改类方法
class 子类 :继承方式 父类
继承方式: - 公有继承
- 保护继承
- 私有继承
点击查看代码
#include <iostream>
class Base
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class son1 : public Base
{
public:
void text()
{
m_A = 1;//public权限
m_B = 2;//protect权限
//m_C = 3;//invalid
}
};
void outext1()
{
son1 s1;
s1.m_A = 1;
//s1.m_B = 2;//invalid
//s1.m_C = 3;//invalid
}
class son2 : protected Base
{
public:
void text()
{
m_A = 1;//public权限
m_B = 2;//protected权限
//m_C = 3;//invalid
}
};
void outext2()
{
son2 s2;
//s1.m_A = 1;//invalid
//s1.m_B = 2;//invalid
//s1.m_C = 3;//invalid
}
class son3 : private Base
{
public:
void text()
{
m_A = 1;//private权限
m_B = 2;//private权限
//m_C = 3;//invalid
}
};
void outext3()
{
son3 s3;
//s1.m_A = 1;//invalid
//s1.m_B = 2;//invalid
//s1.m_C = 3;//invalid
}
class GrandSon3 : public son3
{
public:
void text()
{
//son3是私有继承,所以son3在GrandSon3中都无法访问
//m_A = 1;
//m_B = 2;
//m_C = 3;
}
};
- 父类中私有成员也是被子类继承下去了,只是由编译器隐藏后无法访问
- 继承中构造和析构顺序:
构造时:先调用父类构造函数,再调用子类构造函数
析构时:相反
#include <iostream>
class Base
{
public:
Base()
{
std::cout << "Base构造函数" << std::endl;
}
~Base()
{
std::cout << "Base析构函数" << std::endl;
}
};
class Son : public Base
{
public:
Son()
{
std::cout << "Son构造函数" << std::endl;
}
~Son()
{
std::cout << "Son析构函数" << std::endl;
}
};
int main()
{
Son s;
}
- 继承同名成员处理方式:
子类对象可以直接访问到子类中的成员或函数
子类对象加作用域可以访问到父类中的成员或函数
#include <iostream>
class Base
{
public:
int m_A;
Base()
{
m_A = 100;
}
void text()
{
std::cout << "Base_text()调用" << std::endl;
}
void text(int)
{
std::cout << "Base_text(int)调用" << std::endl;
}
};
class Son : public Base
{
public:
int m_A;
Son()
{
m_A = 200;
}
void text()
{
std::cout << "Son_text()调用" << std::endl;
}
void text(int)
{
std::cout << "Son_text(int)调用" << std::endl;
}
};
int main()
{
Son s;
std::cout << s.m_A << std::endl;//打印子类中的A
std::cout << s.Base::m_A << std::endl;//打印父类中的A
//调用子类中的函数
s.text();
s.text(666);
//调用父类中的函数
s.Base::text();
s.Base::text(888);
}
- 继承同名静态成员处理方式:
有两种方式:
①通过对象
②通过类名
#include <iostream>
class Base
{
public:
static int m_A;
static void text()
{
std::cout << "Base_text()调用" << std::endl;
}
static void text(int)
{
std::cout << "Base_text(int)调用" << std::endl;
}
};
int Base::m_A = 100;
class Son : public Base
{
public:
static int m_A;
static void text()
{
std::cout << "Son_text()调用" << std::endl;
}
static void text(int)
{
std::cout << "Son_text(int)调用" << std::endl;
}
};
int Son::m_A = 200;
int main()
{
Son s;
//通过对象访问
std::cout << s.m_A << std::endl;//打印子类中的A
std::cout << s.Base::m_A << std::endl;//打印父类中的A
//通过类名访问
std::cout << Base::m_A << std::endl;
std::cout << Son::m_A << std::endl;
//调用子类中的函数
s.text();
s.text(666);
Son::text();
//调用父类中的函数
s.Base::text();
s.Base::text(888);
Son::Base::text();
}
- 多继承语法:一个类继承多个类
class 子类 : 继承方式 父类1 , 继承方式 父类2···
若出现同名成员,需要加作用域区分
#include <iostream>
class Base1
{
public:
int m_A;
Base1()
{
m_A = 100;
}
};
class Base2
{
public:
int m_A;
Base2()
{
m_A = 200;
}
};
class Son : public Base1, public Base2
{
public:
int m_C;
int m_D;
Son()
{
m_C = 300;
m_D = 400;
}
};
int main()
{
Son s;
std::cout << sizeof(s) << std::endl;
std::cout << s.Base1::m_A << std::endl;
std::cout << s.Base2::m_A << std::endl;
return 0;
}
- 继承中使用指针:
①父类指针可以指向子类指针
②父类指针只能调用父类方法,不能调用子类方法
③子类指针不可以指向父类指针
点击查看代码
#include <iostream>
class Base
{
private:
int m_A;
int m_B;
public:
Base();
Base(int x,int y);
void out();//父类的out函数
};
Base::Base() : m_A(0),m_B(0) {}
Base::Base(int x,int y) : m_A(x),m_B(y) {}
void Base::out()
{
std::cout << "Base::m_A = " << m_A << " " << "Base::m_B = " << m_B << " ";
}
class Son : public Base
{
private:
int m_B;
public:
Son();
Son(const Base& tp, int C);
Son(int A, int B,int C);
void out();//子类的out函数
};
Son::Son() : Base(), m_B(0) {}
Son::Son(const Base& tp, int C) :Base(tp), m_B(C){}
Son::Son(int A, int B,int C) : Base(A,B), m_B(C) {}
void Son::out()
{
Base::out();
std::cout << "Son::m_B = " << m_B << std::endl;
}
int main()
{
Base b(1, 2);
Son s1(1, 2, 3);
Son s2(Base(4, 5), 6);
Base& x = s1;//父类可以指向子类
//Son& x = b1;//子类不能指向父类
Base& y = b;//父类可以指向父类
Son& z = s2;//子类可以指向子类
//b.out();
//std::cout << std::endl;
//s1.out();
//s2.out();
x.out();//调用父类的out函数
std::cout << std::endl;
y.out();//调用父类的out函数
std::cout << std::endl;
z.out();//调用子类的out函数
return 0;
}
- 虚函数:
①使用关键字virtual
②允许父类指向子类的指针调用子类的虚函数==>子类虚函数重写父类函数
点击查看代码
#include <iostream>
class Base
{
private:
int m_A;
int m_B;
public:
Base();
Base(int x,int y);
virtual void out();//父类的out函数
};
Base::Base() : m_A(0),m_B(0) {}
Base::Base(int x,int y) : m_A(x),m_B(y) {}
void Base::out()
{
std::cout << "Base::m_A = " << m_A << " " << "Base::m_B = " << m_B << " ";
}
class Son : public Base
{
private:
int m_B;
public:
Son();
Son(const Base& tp, int C);
Son(int A, int B,int C);
void out();//子类的out函数
};
Son::Son() : Base(), m_B(0) {}
Son::Son(const Base& tp, int C) :Base(tp), m_B(C){}
Son::Son(int A, int B,int C) : Base(A,B), m_B(C) {}
void Son::out()
{
Base::out();
std::cout << "Son::m_B = " << m_B << std::endl;
}
int main()
{
Base b1(1, 2);
Son s1(1, 2, 3);
Son s2(Base(4, 5), 6);
//父类可以指向子类
Base& x = s1;
Base* x2 = new Son(2, 3, 4);
Base& x3 = *new Son(3, 4, 5);
//子类不能指向父类
//Son& x = b1;
//Son* x = new Base();
//父类可以指向父类
Base& y = b1;
//子类可以指向子类
Son& z = s2;
//现在可以调用子类的out函数!!!
x.out();
x2->out();
x3.out();
//调用父类的out函数
y.out();
std::cout << std::endl;
//调用子类的out函数
z.out();
//需要释放内存
delete x2;
delete &x3;
return 0;
}
虚函数内部原理:
①不使用虚函数:空类大小为1
点击查看代码
#include <iostream>
class Base
{
public:
void out();
};
class Son : public Base
{
public:
void out();
};
void Base::out()
{
std::cout << "I'm Base!" << std::endl;
}
void Son::out()
{
std::cout << "I'm Son!" << std::endl;
}
int main()
{
std::cout << sizeof(Base) << std::endl;
}
①使用虚函数:类内虚函数指针占8位
点击查看代码
#include <iostream>
class Base
{
public:
virtual void out();
};
class Son : public Base
{
public:
void out();
};
void Base::out()
{
std::cout << "I'm Base!" << std::endl;
}
void Son::out()
{
std::cout << "I'm Son!" << std::endl;
}
int main()
{
std::cout << sizeof(Base) << std::endl;
}
- 虚析构函数:
①只需在析构函数定义前加virtual
②只需在父类中使用
③父类的指针指向子类的对象,子类如果申请了堆空间,父类的析构函数释放不到,会造成内存泄漏
④通常给父类提供一个虚析构函数,即使它不需要
点击查看代码
#include <iostream>
class Base
{
private:
int m_A;
int m_B;
public:
Base();
Base(int x,int y);
virtual ~Base();//必须加上virtual
virtual void out();//父类的out函数
};
Base::Base() : m_A(0),m_B(0) {}
Base::~Base()
{
std::cout << "释放Base!" << std::endl;
}
Base::Base(int x,int y) : m_A(x),m_B(y) {}
void Base::out()
{
std::cout << "Base::m_A = " << m_A << " " << "Base::m_B = " << m_B << " ";
}
class Son : public Base
{
private:
int m_B;
public:
Son();
~Son();
Son(const Base& tp, int C);
Son(int A, int B,int C);
void out();//子类的out函数
};
Son::Son() : Base(), m_B(0) {}
Son::~Son()
{
std::cout << "释放Son!" << std::endl;
}
Son::Son(const Base& tp, int C) :Base(tp), m_B(C){}
Son::Son(int A, int B,int C) : Base(A,B), m_B(C) {}
void Son::out()
{
Base::out();
std::cout << "Son::m_B = " << m_B << std::endl;
}
int main()
{
Base* a = new Son(1, 2, 3);
delete a;
return 0;
}
- 纯虚析构:
区别:
纯虚析构,则该类属于抽象类,无法实例化对象
语法:
virtual ~类名() = 0;
类名::类名~类名(){}
点击查看代码
#include <iostream>
class Base
{
public:
Base()
{
std::cout << "构造函数调用" << std::endl;
}
virtual ~Base() = 0;//纯虚析构函数
virtual void func() = 0;
};
Base::~Base()
{
std::cout << "纯虚析构函数调用" << std::endl;
}
class Son : public Base
{
public:
void func()
{
std::cout << "func()调用" << std::endl;
}
};
int main()
{
//Base b;//无法实例化对象
Son s;
s.func();
Base* b = new Son;
b->func();
delete b;
return 0;
}
- 虚继承:
菱形继承:两个子类继承一个父类,同时另一个子类继承这两个子类
问题:
①产生二义性
②继承了两份数据,实际只需要一份
使用虚继承解决:
点击查看代码
#include <iostream>
class Base
{
public:
int m_Age;
};
class son1 : virtual public Base//加关键字virtual(Base为虚基类)
{
};
class son2 : virtual public Base//加关键字virtual(Base为虚基类)
{
};
class son : public son1, public son2//多继承(不建议使用)
{
};
int main()
{
son s;
s.m_Age = 10;
std::cout << s.Base::m_Age << " " << s.son1::m_Age << " " << s.son2::m_Age << std::endl;
s.son1::m_Age = 20;
s.son2::m_Age = 30;
std::cout << s.Base::m_Age << " " << s.son1::m_Age << " " << s.son2::m_Age << std::endl;
return 0;
}
- 多态:
静态多态(编译阶段确定函数地址):函数重载 和 函数运算符 属于静态多态,复用函数名
动态多态(运行阶段确定函数地址):派生类 和 虚函数 属于动态多态 - 纯虚函数:
①在虚函数后面加上=0
②有纯虚函数的类称为抽象类
③无法实例化对象
④子类必须重写抽象类中的纯虚函数,否则也属于抽象类
点击查看代码
#include <iostream>
class Base
{
public:
virtual void func() = 0;
};
class Son : public Base
{
public:
void func()
{
std::cout << "func()调用" << std::endl;
}
};
int main()
{
//Base b;//无法实例化对象
Son s;
s.func();
Base* b = new Son;
b->func();
delete b;
return 0;
}
- 友元与继承:
友元不是成员函数,无法继承
但子类可以通过强制类型转换
使用父类的友元
点击查看代码
#include <iostream>
class Base
{
private:
int m_base1;
int m_base2;
public:
Base(int b1 = 0, int b2 = 0);
Base(const Base& b);
friend std::ostream& operator<<(std::ostream& os,const Base& b);
};
class Son: public Base
{
private:
int m_son;
public:
Son(int b1 = 0, int b2 = 0, int son = 0);
Son(Base& b, int son);
friend std::ostream& operator<<(std::ostream& os,const Son& s);
};
Base::Base(int b1, int b2)
{
m_base1 = b1;
m_base2 = b2;
}
Base::Base(const Base& b)//浅拷贝(可不写)
{
m_base1 = b.m_base1;
m_base2 = b.m_base2;
}
std::ostream& operator<<(std::ostream& os,const Base& b)
{
os << "base1 = " << b.m_base1 << std::endl;
os << "base2 = " << b.m_base2 << std::endl;
return os;
}
Son::Son(int b1, int b2, int son) :Base(b1, b2)
{
m_son = son;
}
Son::Son(Base& b, int son) :Base(b)//使用浅拷贝
{
m_son = son;
}
//invalid!!!
//Son::Son(Base& b, int son)
//{
// Base(b);
// m_son = son;
//}
//invalid!!!
//Son::Son(int b1, int b2, int son)
//{
// Base(b1, b2);
// m_son = son;
//}
std::ostream& operator<<(std::ostream& os, const Son& s)
{
os << (const Base&)s;//使用强制类型转换
os << "son = " << s.m_son << std::endl;
return os;
}
int main()
{
Base b(2,3);
std::cout << b;
Son s(4, 5, 6);
std::cout << s;
}
valarray类
用于处理数值的类,包含很多方法
点击查看代码
#include <iostream>
#include <valarray>//需要包含头文件<valarray>
int main()
{
std::valarray<int> v0(3);//3个大小为0的元素
std::valarray<int> v1(10,3);//3个大小设置为10的元素
std::valarray<double> v2={1,2,3,4};
long x1[3]={3,4,5};
std::valarray<long> x2(x1,3);
//遍历
for(int i=0;i<v2.size();i++)
{
std::cout<<v2[i]<<" ";
}
std::cout<<std::endl;
std::cout<<"max:"<<v2.max()<<std::endl;//最小值
std::cout<<"min:"<<v2.min()<<std::endl;//最大值
std::cout<<"sum:"<<v2.sum()<<std::endl;//求和
std::cout<<"size:"<<v2.size()<<std::endl;//求元素个数
//交换(两个类的元素个数必须相同)
std::cout<<"交换"<<std::endl;
v1.swap(v0);
for(int i=0;i<v0.size();i++)
{
std::cout<<v0[i]<<" ";
}
for(int i=0;i<v1.size();i++)
{
std::cout<<v1[i]<<" ";
}
std::cout<<std::endl;
std::valarray<int> v(3);
std::cout<<"相减:"<<std::endl;
v=v1-v0;//加减法操作
for(int i=0;i<v.size();i++)
{
std::cout<<v[i]<<" ";
}
std::cout<<std::endl;
std::valarray<double> v3(10,3);
std::cout<<"求平方根:"<<std::endl;
v3=std::sqrt(v3);//求平方根
for(int i=0;i<v3.size();i++)
{
std::cout<<v3[i]<<" ";
}
}
异常
①调用abort()
:异常终止函数
需要包含头文件cstdlib
点击查看代码
#include <iostream>
#include <cstdlib>
double division(int a, int b)
{
if (b == 0)
{
abort();
}
return (a / b);
}
int main()
{
int x = 50;
int y = 0;
double z = 0;
z = division(x, y);//保护代码
return 0;
}
②异常处理:
throw
:抛出异常
catch
:捕获异常
try
:try块中放置可能抛出异常的代码
点击查看代码
#include <iostream>
double division(int a, int b)
{
if (b == 0)
{
throw "Division by zero condition!";//抛出异常
}
return (a / b);
}
int main()
{
int x = 50;
int y = 0;
double z = 0;
try
{
z = division(x, y);//保护代码
}
catch (const char* msg)//捕获异常
{
std::cerr << msg << std::endl;
}
std::cout << z;
return 0;
}
智能指针
自动释放new出来的内存,从而避免内存泄露
出现内存泄露:
①忘记手动释放
②虽然写了delete,但发生异常,函数提前结束,导致内存没用释放
- auto_ptr:在C++98中使用,C++11弃用
- unique_ptr:独占式指针,只能有一个指针指向同一个对象
- shared_ptr:共享式指针,可以有多个指针指向同一个对象
- weak_ptr:用来解决shared_ptr相互引用导致的锁死问题
⑴auto_ptr:
使用方法:
①memory头文件
②auto_ptr<类型> 变量名(new 类型)
auto_ptr<string> str(new string("----"));
auto_ptr<vector<int>> av(new vector<int>());
auto_ptr<int> array(new int[10]);
点击查看代码
#include <iostream>
#include <memory>
class Test
{
private:
int debug = 20;
public:
Test()
{
std::cout << "Test构造函数" << std::endl;
}
~Test()
{
std::cout << "Test析构函数" << std::endl;
}
int getdebug()
{
return this->debug;
}
};
int main()
{
Test* t1 = new Test;
std::cout << t1->getdebug() << std::endl;
delete t1;//手动释放
std::cout << "----------------" << std::endl;
std::auto_ptr<Test> t2(new Test);//自动释放
std::cout << t2->getdebug() << std::endl;//可以像普通指针一样使用
return 0;
}
- 智能指针的常用函数:
get():
获取智能指针托管的指针地址
std::auto_ptr<Test> t(new Test);
Test* temp=t.get();
std::cout<<temp->getdebug()<<std::endl;
realse():
取消智能指针对动态内存的托管
智能指针不再对该指针进行管理,改由管理员进行管理
std::auto_ptr<Test> t(new Test);
Test* temp = t.release();
std::cout << temp->getdebug() << std::endl;
//std::cout << t->getdebug() << std::endl;//t无法使用(智能指针不再托管)
delete temp;//temp需要手动释放
reset():
重置智能指针托管的内存地址
auto_ptr<int> t(new int(10));
t.reset();//释放掉智能指针托管的指针内存,并将其置为NULL
t.reset(new int(20));//释放掉智能指针托管的指针内存,并将参数指针取代之
点击查看代码
#include <iostream>
#include <memory>
#include <vector>
#include <string>
class Test
{
private:
int debug = 20;
public:
Test()
{
std::cout << "Test构造函数" << std::endl;
}
~Test()
{
std::cout << "Test析构函数" << std::endl;
}
int getdebug()
{
return this->debug;
}
};
int main()
{
std::auto_ptr<Test> t(new Test);
t.reset();//释放掉智能指针托管的指针内存,并将其置NULL
//提前调用析构函数
//std::cout << t->getdebug() << std::endl;//invalid
std::cout << "-----------------" << std::endl;
std::auto_ptr<int> temp(new int(10));
std::cout << *temp << std::endl;//valid
temp.reset(new int(20));//释放掉智能指针托管的指针内存,并将参数指针取代之
std::cout << *temp << std::endl;//valid
std::cout << "-----------------" << std::endl;
std::auto_ptr<Test> t2(new Test);
t2.reset(new Test);//构造新指针,智能指针提前释放
std::cout << t2->getdebug() << std::endl;//valid
std::cout << "-------------" << std::endl;
std::auto_ptr<std::string> s1;
std::auto_ptr<std::string> s2;
std::string* str = new std::string("wwwww");
//s1.reset(str);//
//s2.reset(str);//s1和s2将会释放相同的资源,导致程序崩溃
return 0;
}
- 注意:
①不要将auto_ptr变量定义为全局变量或指针
std::auto_ptr<Test>* t = new std::auto_ptr<Test>(new Test);//invalid
②auto_ptr智能指针之间不要相互赋值
std::auto_ptr<Test> t1(new Test);
std::auto_ptr<Test> t2(new Test);
t1 = t2;
- 被C++11抛弃原因:
①赋值会导致智能指针所有权改变
点击查看代码
#include <iostream>
#include <memory>
#include <vector>
#include <string>
class Test
{
private:
int debug = 20;
public:
Test()
{
std::cout << "Test构造函数" << std::endl;
}
~Test()
{
std::cout << "Test析构函数" << std::endl;
}
int getdebug()
{
return this->debug;
}
};
int main()
{
std::auto_ptr<Test> t1(new Test);
std::auto_ptr<Test> t2(new Test);
t1 = t2;//导致t2的指针被释放(t1托管t2的指针,t2放弃了托管)
std::cout << t1->getdebug() << std::endl;
//std::cout << t2->getdebug() << std::endl;//invalid
std::cout << "---------------" << std::endl;
std::auto_ptr<std::string> p1(new std::string("I'm Li Ming!"));
std::auto_ptr<std::string> p2(new std::string("I'm age 22."));
std::cout << "p1:" << p1.get() << std::endl;
std::cout << "p2:" << p2.get() << std::endl;
p1 = p2;//p1先将自己原先托管的指针释放,然后托管p2所托管的指针,并将p2所托管的指针置为NULL
std::cout << "p1 = p2 赋值后:" << std::endl;
std::cout << "p1:" << p1.get() << std::endl;
std::cout << "p2:" << p2.get() << std::endl;
return 0;
}
②在STL容器中使用auto_ptr存在重大风险,因为容器内的元素必须支持复制和赋值操作
③不支持对数组的内存管理
std::auto_ptr<int []> arr(new int[5]);//invalid
⑵unique_ptr:
- 用法:
①无法进行左值赋值和构造,但允许右值赋值
点击查看代码
#include <iostream>
#include <memory>
#include <vector>
#include <string>
class Test
{
private:
int debug = 20;
public:
Test()
{
std::cout << "Test构造函数" << std::endl;
}
~Test()
{
std::cout << "Test析构函数" << std::endl;
}
int getdebug()
{
return this->debug;
}
};
int main()
{
std::auto_ptr<int> i1(new int(10));
std::auto_ptr<int> i2(new int(20));
i1 = i2;//i2被释放
std::auto_ptr<int> i3(i1);//i1被释放
std::unique_ptr<int> u1(new int(10));
std::unique_ptr<int> u2(new int(20));
//u1 = u2;//左值赋值invaild
u1 = std::move(u2);//右值赋值(u2被释放)
//std::unique_ptr<int> u3(u1);//左值赋值invalid
std::unique_ptr<int> u3(move(u1));//右值赋值(u1被释放)
return 0;
}
②在STL容器中使用unique_ptr不允许直接赋值
③支持数组的内存管理
std::unique_ptr<int[]> arr(new int[10]);//valid
⑶shared_ptr:
共享多个指针变量
STL中复制和赋值操作可用于shared_ptr,但不能用于unique_ptr和auto_ptr
当复制或拷贝时,引用计数加1
当智能指针析构时,引用计数减1
如果计数为零,代表已经没有指针指向这块内存,那么就释放它
use_count()函数:
可以获得当前托管指针的引用计数
点击查看代码
#include <iostream>
#include <memory>
#include <vector>
#include <string>
class Test
{
private:
int debug = 20;
std::string m_str;
public:
Test(std::string str)
{
m_str = str;
std::cout << str;
std::cout << "的Test构造函数" << std::endl;
}
~Test()
{
std::cout << m_str;
std::cout << "的Test析构函数" << std::endl;
}
int getdebug()
{
return this->debug;
}
};
int main()
{
std::shared_ptr<Test> t1;
std::shared_ptr<Test> t2(new Test("t2"));
std::cout << "------------------\n";
std::cout << t1.use_count() << std::endl;
std::cout << t2.use_count() << std::endl;
std::cout << "------------------\n";
t1 = t2;//共享(t2指针不会释放)
std::cout << t1.use_count() << std::endl;
std::cout << t2.use_count() << std::endl;
std::cout << "------------------\n";
std::shared_ptr<Test> t3(t1);
std::cout << t1.use_count() << std::endl;
std::cout << t2.use_count() << std::endl;
std::cout << t3.use_count() << std::endl;
std::cout << "------------------\n";
t1.reset();//将t1重置为空指针
std::cout << t1.use_count() << std::endl;//管理对象引用计数为0
std::cout << t2.use_count() << std::endl;//管理对象引用计数减1
std::cout << t3.use_count() << std::endl;//管理对象引用计数减1
return 0;
}
初始化:
方式一:构造函数
shared_ptr<int> i1(new int(10));
shared_ptr<int> i2(i1);
方式二:使用make_shared(分配内存效率更高)
std::shared_ptr<int> u1 = std::make_shared<int>(2);
std::shared_ptr<std::string> s1 = std::make_shared<std::string>("www");
std::shared_ptr<Test> t1 = std::make_shared<Test>("www");
swap()交换函数:
交换p1和p2管理的对象并交换引用计数
std::swap(p1,p2);
p1.swap(p2);
点击查看代码
#include <iostream>
#include <memory>
#include <vector>
#include <string>
int main()
{
std::shared_ptr<int> t1 = std::make_shared<int>(1);
std::shared_ptr<int> t2 = std::make_shared<int>(2);
std::shared_ptr<int> t3 = std::make_shared<int>(3);
t1 = t3;
//引用计数
std::cout << t1.use_count() << " " << t2.use_count() << " " << t3.use_count() << std::endl;
std::cout << *t1 << std::endl;
std::cout << *t2 << std::endl;
std::cout << *t3 << std::endl;
//t1.swap(t2);
std::swap(t1, t2);
std::cout << *t1 << std::endl;
std::cout << *t2 << std::endl;
std::cout << *t3 << std::endl;
//引用计数
std::cout << t1.use_count() << " " << t2.use_count() << " " << t3.use_count() << std::endl;
return 0;
}
- shared_ptr使用陷阱:注意避免对象交叉使用智能指针
点击查看代码
#include <iostream>
#include <string>
#include <memory>
using namespace std;
class Girl;
class Boy
{
private:
shared_ptr<Girl> girlFriend;
public:
Boy()
{
cout << "Boy 构造函数" << endl;
}
~Boy()
{
cout << "~Boy 析构函数" << endl;
}
void setGirlFriend(shared_ptr<Girl> _girlFriend)
{
this->girlFriend = _girlFriend;
}
};
class Girl
{
private:
shared_ptr<Boy> boyFriend;
public:
Girl()
{
cout << "Girl 构造函数" << endl;
}
~Girl()
{
cout << "~Girl 析构函数" << endl;
}
void setBoyFriend(shared_ptr<Boy> _boyFriend)
{
this->boyFriend = _boyFriend;
}
};
int main(void)
{
shared_ptr<Boy> spBoy(new Boy());
shared_ptr<Girl> spGirl(new Girl());
// 陷阱用法
spBoy->setGirlFriend(spGirl);
spGirl->setBoyFriend(spBoy);
// 此时boy和girl的引用计数都是2
//但是并没有释放内存
return 0;
}
⑷weak_ptr:
用来解决shared_ptr使用陷阱
STL标准库
- STL六大组件:
容器、算法、迭代器、仿函数、适配器、空间适配器 - 迭代器:
不同容器有不同的迭代器
用于对各种容器内元素的访问
可以理解为指针
常用迭代器:双向迭代器、随机访问迭代器
方法: 容器名<类型名>::iterator 迭代器名;
vector::iterator p;(p类似于指针)
拿到vector容器的迭代器类型 begin()和end():
v.begin()返回指向容器第一个数据的迭代器
v.end()返回指向容器最后一个元素的下一个位置的迭代器
std::vector<int> v;
std::vector<int>::iterator pBegin = v.begin();
//std::vector<int>::iterator pBegin = begin(v);
std::vector<int>::iterator pEnd = v.end();
//std::vector<int>::iterator pEnd = end(v);
点击查看代码
#include <iostream>
#include <vector>
#include <algorithm>//算法
void Myprint(int val)
{
std::cout << val << std::endl;
}
int main()
{
std::vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
std::vector<int>::iterator pBegin = v.begin();
std::vector<int>::iterator pEnd = v.end();
//第一种遍历方式:
while (pBegin != pEnd)
{
std::cout << *pBegin << std::endl;
pBegin++;
}
//第二种遍历方式:
for (std::vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
std::cout << *it << std::endl;
}
//第三种遍历方式:
//使用STL提供标准遍历算法
std::for_each(v.begin(), v.end(), Myprint);
return 0;
}
string
- 构造函数:
#include <iostream>
#include <string>
using std::string;
int main()
{
string str1;//定义空string容器
string str2("abc");//将abc作为初值
string str3 = "abc";//同上
string str4 = { "abc" };//同上
string str5{ "abc" };//同上
string str6{ 'a','b','c' };//同上
string str7(10, 'a');//将10个a作为初值
string str8(str7);//str8拷贝str7中的所有元素
string str9 = str7;//同上
string str10(str2, 1);//str10拷贝str2[1]~str[n-1]
string str11(str2, 1, 2);//str10拷贝从str2[1]起的2个元素
string str12(str2.begin(), str2.end());//拷贝区间内元素
}
-
迭代器:
string::iterator it=str.begin();
auto it=str.begin();
str.begin()
:返回迭代器,指向第一个元素
str.end()
:返回迭代器,指向末尾元素的下一个位置
str.cbegin()
:返回迭代器,指向第一个元素,类型为const(不能修改元素的值)
str.rbegin()
:返回迭代器,指向反向迭代的第一个元素
str.rend()
:返回迭代器,指向反向迭代的末尾元素的下一个位置
str.crbegin()
:返回迭代器,指向反向迭代的第一个元素,类型为const -
常用函数:
点击查看代码
#include <iostream>
#include <string>
#include <fstream>
using std::string;
int main()
{
string str = "abcde";
string str1 = "12345";
//at:下标
char ch1 = str[3];
char ch2 = str.at(3);
//assign:赋值函数
str.assign(10, 's');
//将10个s赋值给str
//str="ssssssssss"
str.assign(str1);
//将str1赋值给str
//str=12345
str.assign(str1, 2);
//将str1[2]~str1[n-1]赋值给str
//str=345
str.assign(str1, 1, 3);
//将从str1[1]起的3个元素赋值给str
//str=234
str.assign(str1.begin() + 1, str1.end() - 1);
//将区间内的元素赋值给str
//str=234
//连接符
//=:字符串赋值
str = str1;
//str=12345
str = "abcde";
//str=abcde
//+和+=:连接字符串
str += str1;
//str=abcde12345
str += "sss";
//str=abcde12345sss
str += '6';
//str=abcde12345sss6
//<、>、>=、<=、==、!=:字符串比较
string s1 = "abc";
string s2 = "abb";
int result;
result = s1 > s2;//1
result = s1 < s2;//0
//<<、>>:输入输出字符串
string s;
//std::cin >> s;
//std::cout << s;
//swap:交换函数
s1.swap(s2);
//s1="abb"
//s2="abc"
//push_back:末尾添加字符(并非字符串)
str = "ab";
str.push_back('c');
//str="abc"
//pop_back:删除最后一个字符
str.pop_back();
//str="ab"
//front:返回第一元素
char c=str.front();
//c=a
//back:返回末尾元素
c = str.back();
//c=b
//clear:清空容器
str.clear();
//empty:判断是否为空
result = str.empty();
//result=1
//length:返回字符串str的长度
str = "abc";
result = str.length();
//result=3
//size:返回容器内元素个数
result = str.size();
//result=3
//resize:设置str的size值
str.resize(5);
//size=5
//str="abc ",新空间用空格代替
str.resize(2);
//size=2
//str="ab",多余部分被截取
str.resize(5, 's');
//新空间用s代替
//str="absss"
//capacity:返回str可容纳的字符数(大小只能为16*n-1)
//str="abc" 返回:15
//str="abcabcabcabcab16" 返回:31
result = str.capacity();
//reserve:设置str的capacity
str.reserve(16);
//capacity > 16 && capacity = 16 * n - 1
//所以capacity=31
//insert:插入函数
str = "abc";
str.insert(1, 3, 'x');
//在第1个位置插入3个x
//str="axxxbc"
str = "abc";
str.insert(2, "123");
//在第2个位置插入字符串123
//str="ab123c"
str = "abc";
str1 = "123";
str.insert(2, str1);
//在第2个位置插入str1
//str="ab123c"
str = "abc";
str1 = "123456";
str.insert(2, str1, 3);
//在第2个位置插入str[3]~str[n-1]
//str=ab456c
str = "abc";
str1 = "123456";
str.insert(2, str1, 1, 4);
//在第2个位置插入从str[1]起的4个元素
//str=ab2345c
str = "abc";
str.insert(str.end(), 's');
//在末尾插入字符s
//str="abcs"
str = "abc";
str.insert(str.end(), 3, 's');
//在末尾插入3个字符s
//str="abcsss"
str = "abc";
str1 = "123";
str.insert(str.end(), str1.begin(), str1.end());
//在末尾插入str1区间的元素
//str="abc123"
//append:连接函数
str = "abc";
str.append(3, 's');
//在末尾加3个字符s
//str="abcsss"
str = "abc";
str1 = "123";
str.append(str1);
//在末尾加str1
//str="abc123"
str = "abc";
str1 = "123456";
str.append(str1, 2);
//在末尾加str1[2]~str1[n-1]
//str="abc3456"
str = "abc";
str1 = "123456";
str.append(str1, 2, 3);
//在末尾加从str1[2]起的3个元素
//str="abc345"
str = "abc";
str1 = "123456";
str.append(str1.begin() + 1, str1.end() - 1);
//在末尾加str1区间的元素
//str="abc2345"
//erase:删除函数
str = "abcdef";
str.erase(3);
//删除str[3]到str[n-1]
//str="abc"
str = "abcdef";
str.erase(3, 2);
//删除从str[3]起的2个元素
//str="abcf"
str = "abcdef";
string::iterator it1=str.erase(str.begin()+2);
//删除指向的元素,返回指向下一个元素的迭代器
//str="abdef"
//返回指向d的迭代器
str = "abcdef";
auto it=str.erase(str.begin() + 1, str.end() - 1);
//删除区间的元素,返回指向下一个元素的迭代器
//str="af"
//返回指向f的迭代器
str = "abcdef";
str.erase(str.begin(), str.end());
//删除str所有元素
//str.empty()==1
//replace:替换函数
str = "abcdefg";
str.replace(2, 3, 4, 's');
//将从str[2]起的3个元素替换成4个s
//str="abssssfg"
str = "abcdefg";
str1 = "123456";
str.replace(2, 3, str1);
//将从str[2]起的3个元素替换成str1
//str="ab123456fg"
str = "abcdefg";
str1 = "123456";
str.replace(2, 3, str1, 4);
//将从str[2]起的3个元素替换成str1[4]~str1[n-1]
//str="ab56fg"
str = "abcdefg";
const char* ch = "123456";//char*类型字符串
str.replace(2, 3, ch, 4);
//将从str[2]起的3个元素替换成str1的前4个字符
//str="ab1234fg"
str = "abcdefg";
str1 = "123456";
str.replace(2, 3, str1, 3, 2);
//将从str[2]起的3个元素替换成从str1[3]起2个元素
//str="ab45fg"
str = "abcdefg";
str.replace(str.begin() + 1, str.end() - 1, 3, 's');
//将区间内的元素替换成3个s
//str="asssg"
str = "abcdefg";
str1 = "123456";
str.replace(str.begin() + 1, str.end() - 1, str1);
//将区间内的元素替换成str1
//str="a123456g"
str = "abcdefg";
ch = "123456";
str.replace(str.begin() + 1, str.end() - 1, ch);
//将区间内的元素替换成ch
//str="a123456g"
str = "abcdefg";
ch = "123456";
str.replace(str.begin() + 1, str.end() - 1, ch, 3);
//将区间内的元素替换成ch的前3个字符
//str="a123g"
//copy:复制函数
str = "abcdefg";
char S0[20]="123456";
str.copy(S0, 3);
//将S0前3个字符替换成str前3个字符
//S0="abc456"
str = "abcdefg";
char S1[20] = "123456";
str.copy(S1, 3, 2);
//将S1前3个字符替换成从str[2]起的3个字符
//S1="cde456"
//find:查找函数
str = "abcdefg";
result = str.find('c');
//返回字符c在str中首次出现的位置
//返回2
str = "abcdefg";
result = str.find('c', 2);
//返回字符c在str[2]~str[n-1]中首次出现的位置
//返回2
str = "abcdefg";
char S3[10] = "de";
result = str.find(S3);
//返回字符串S3在str中首次出现的位置
//返回3
str = "abcdefg";
char S4[10] = "de";
result = str.find(S4,2);
//返回字符串S4在str[2]~str[n-1]中首次出现的位置
//返回3
str = "abcdefg";
char S5[10] = "de";
result = str.find(S5, 2, 1);
//返回字符串S5[0]~S5[1]在str[2]~str[n-1]中首次出现的位置
//返回3
str = "abcdefg";
str1 = "de";
result = str.find(str1);
//返回字符串str1在str中首次出现的位置
//返回3
str = "abcdefg";
str1 = "de";
result = str.find(str1, 2);
//返回字符串str1在str[2]~str[n-1]中首次出现的位置
//返回3
str = "abababa";
str1 = "ab";
result = str.rfind(str1);
//反向查找str1在str中首次出现的位置
//返回4
str = "abababab";
str1 = "ab";
//反向查找str1在str[0]~str[2+str1.size()-1]中首次出现的位置
result = str.rfind(str1,2);//反向查找ab在abab首次出现的位置,返回2
result = str.rfind(str1, 4);//反向查找ab在ababab首次出现的位置,返回4
result = str.rfind(str1, 5);//反向查找ab在abababa首次出现的位置,返回4
result = str.rfind(str1, 6);//反向查找ab在abababa首次出现的位置,返回6
str = "abcdefg";
str1 = "ec";
result = str.find_first_of(str1);
//返回str1中任意一个字符在str中首次出现的位置
//返回2
str = "abcdefg";
str1 = "bac";
result = str.find_first_not_of(str1);
//返回除str1以外的任意一个字符在str中首次出现的位置
//返回3
str = "abcdefg";
str1 = "ec";
result = str.find_last_of(str1);
//返回str1中任意一个字符在str中最后一次出现的位置
//返回4
str = "abcdefg";
str1 = "gfd";
result = str.find_last_not_of(str1);
//返回除str1以外的任意一个字符在str中最后一次出现的位置
//返回4
//substr:查找子串
str = "abcdefg";
str.substr(2);
//返回str[2]~str[n-1]
//子串="cdefg"
str = "abcdefg";
str.substr(2, 3);
//返回从str[2]起的3个元素
//子串="cde"
//getline:读取字符串
str.clear();
std::getline(std::cin, str);
std::cout << str << std::endl;
//读取一行(一直读取直到换行符)
str.clear();
std::getline(std::cin, str, '.');
std::cout << str << std::endl;
//一直读取直到'.'
//c_str:返回一个指向C风格字符串的指针
string filename;
std::ofstream fout;
std::cout << "Enter the file name: ";
std::cin >> filename;
fout.open(filename.c_str());
//打开文件的open()操作要求使用C风格字符串作为参数
return 0;
}
vector
- 构造函数:
#include <iostream>
#include <vector>
using std::vector;
int main()
{
vector<int> v;//定义空vector容器
vector<std::string> vstr;//定义string类的vector容器
vector<vector<int>> vv;//定义二维数组
vector<int> v1(10);//定义10个元素的数组,每个元素默认值为0
vector<int> v2(10, 2);//定义10个2
vector<int> v3 = { 1,2,3,4 };//初始化为1 2 3 4
vector<int> v4{ 1,2,3,4 };//同上
vector<int> v5(v4);//v5拷贝v4的内容
vector<int> v6 = v4;//同上
vector<int> v7(v4.begin()+1, v4.end()-1);//拷贝区间的元素
}
-
迭代器:
vector<int>::iterator it = v.begin();
auto it = v.begin();
v.begin()
:返回迭代器,指向第一个元素
v.end()
:返回迭代器,指向末尾元素的下一个位置
v.cbegin()
:返回迭代器,指向第一个元素,类型为const(不能修改元素的值)
v.rbegin()
:返回迭代器,指向反向迭代的第一个元素
v.rend()
:返回迭代器,指向反向迭代的末尾元素的下一个位置
v.crbegin()
:返回迭代器,指向反向迭代的第一个元素,类型为const -
常用函数:
点击查看代码
#include <iostream>
#include <vector>
using std::vector;
int main()
{
vector<int> v1 = { 1,2,3,4,5 };
vector<int> v;
int result;
//at:下标
result = v1.at(1);
//result = v1[1];
//assign:赋值函数
v1 = { 1,2,3,4 };
v1.assign(2, 1);
//将2个1赋值给v1
//v1="1 1"
v1 = { 1,2,3,4 };
v = {};
v.assign(v1.begin() + 1, v1.end() - 1);
//将区间内的元素赋值给v
//v="2 3"
//swap:交换函数
v = { 1,2 };
v1 = { 3,4 };
v.swap(v1);
//交换v和v1的内容
//v="3 4"
//v1="1 2"
//push_back:末尾添加元素
v = { 1,2 };
v.push_back(3);
v.push_back(4);
v.push_back(5);
//在末尾添加3 4 5
//v="1 2 3 4 5"
//pop_back:删除末尾元素
v = { 1,2,3,4,5 };
v.pop_back();
v.pop_back();
v.pop_back();
//删除末尾的3,4,5
//v="1 2"
//front:返回第一元素
v = { 1,2,3,4,5 };
result = v.front();
//result = 1
//back:返回末尾元素
v = { 1,2,3,4,5 };
result = v.back();
//result = 5
//clear:清空容器
v = { 1,2,3,4,5 };
v.clear();
//v=""
//empty:判断是否为空
result = v.empty();
//为空返回true
//否则返回false
//result = 1
//size:返回元素个数
v = { 1,2,3,4,5 };
result = v.size();
//result = 5
//capacity:返回容器容量
vector<int> v2 = { 1,2,3 };
result = v2.capacity();
//result = 3
//resize:重新设置size的值
v = { 1,2,3,4,5 };
v.resize(3);
//v="1 2 3"
v = { 1,2,3,4,5 };
v.resize(10);
//v="1 2 3 4 5 0 0 0 0 0"
v = { 1,2,3,4,5 };
v.resize(10, 8);
//用8替换多余的部分
//reserve:重新设置capacity的值
vector<int> v3 = { 1,2,3 };
v3.reserve(5);
//v3.reserve()=5
//size的值不变
//insert:插入函数
v = { 1,2,3 };
v.insert(v.begin(), 6);
//在位置前插入6
//v="6 1 2 3"
v = { 1,2,3 };
v.insert(v.begin() + 1, 3, 6);
//在位置前插入3个6
//v="1 6 6 6 2 3"
v = { 1,2,3 };
v1 = { 6,6,6 };
v.insert(v.begin() + 2, v1.begin(), v1.end());
//在位置前插入区间元素
//v="1 2 6 6 6 3"
//emplace:插入函数
//相比于push_back和insert,emplace速度更快
v = { 1,2,3 };
v.emplace(v.begin(), 0);
//在位置之前插入0
//相当于v.insert(v.begin(),0);
//v="0 1 2 3"
v = { 1,2,3 };
v.emplace_back(4);
//在末尾插入元素4
//相当于v.push_back(4);
//v="1 2 3 4"
//erase:删除元素
v = { 1,2,3 };
auto it = v.erase(v.begin() + 1);
//删除位置上的元素,返回指向下一个元素的迭代器
//v="1 3"
//*it = 3
v = { 1,2,3,4,5 };
it=v.erase(v.begin() + 1, v.end() - 1);
//删除区间元素,返回指向下一个元素的迭代器
//v="1 5"
//*it = 5
return 0;
}
deque
与vector区别:deque两端都可以进行增删操作
deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据
所以deque没有capacity函数
- 构造函数:
#include <iostream>
#include <deque>
using std::deque;
int main()
{
deque<int> d;//定义空的int类型数组
deque<std::string> dstr;//定义空的string类型数组
deque<deque<int>>dd;//定义int型二维数组
deque<int> d1(10);//定义10个元素的数组,每个元素默认为0
deque<int> d2(10, 5);//定义10个元素的数组,每个元素为5
deque<int> d3 = { 1,2,3,4,5 };//定义5个元素的数组,初始化为1 2 3 4 5
deque<int> d4{ 1,2,3,4,5 };//同上
deque<int> d5(d4);//d5拷贝d4的内容
deque<int> d6 = d4;//同上
deque<int> d7(d4.begin(), d4.end());//d6拷贝d4区间的内容
}
-
迭代器:
deque<int>::iterator it = d.begin();
auto it = d.begin();
d.begin()
:返回迭代器,指向第一个元素
d.end()
:返回迭代器,指向末尾元素的下一个位置
d.cbegin()
:返回迭代器,指向第一个元素,类型为const(不能修改元素的值)
d.rbegin()
:返回迭代器,指向反向迭代的第一个元素
d.rend()
:返回迭代器,指向反向迭代的末尾元素的下一个位置
d.crbegin()
:返回迭代器,指向反向迭代的第一个元素,类型为const -
常用函数:
点击查看代码
#include <iostream>
#include <deque>
using std::deque;
int main()
{
deque<int> d;
deque<int> d1 = { 1,2,3 };
int result;
//at:下标
result = d1.at(1);
//result = d1[1];
//assign:赋值函数
d1 = { 1,2,3,4 };
d1.assign(2, 1);
//将2个1赋值给v1
//d1="1 1"
d1 = { 1,2,3,4 };
d = {};
d.assign(d1.begin() + 1, d1.end() - 1);
//将区间内的元素赋值给v
//d="2 3"
//swap:交换函数
d = { 1,2 };
d1 = { 3,4 };
d.swap(d1);
//交换d和d1的内容
//d="3 4"
//d1="1 2"
//push_back:末尾添加元素
d = { 1,2 };
d.push_back(3);
d.push_back(4);
d.push_back(5);
//在末尾添加3 4 5
//d="1 2 3 4 5"
//pop_back:删除末尾元素
d = { 1,2,3,4,5 };
d.pop_back();
d.pop_back();
d.pop_back();
//删除末尾的3,4,5
//d="1 2"
//push_front:头部添加元素
d = { 1,2,3 };
d.push_front(4);
d.push_front(5);
d.push_front(6);
//在头部添加6 5 4
//d="6 5 4 1 2 3"
//pop_front:删除头部元素
d = { 1,2,3,4,5 };
d.pop_front();
d.pop_front();
d.pop_front();
//删除头部1,2,3
//d="4 5"
//front:返回第一元素
d = { 1,2,3,4,5 };
result = d.front();
//result = 1
//back:返回末尾元素
d = { 1,2,3,4,5 };
result = d.back();
//result = 5
//clear:清空容器
d = { 1,2,3,4,5 };
d.clear();
//d=""
//empty:判断是否为空
result = d.empty();
//为空返回true
//否则返回false
//result = 1
//size:返回元素个数
d = { 1,2,3,4,5 };
result = d.size();
//result = 5
//deque无capacity函数
//resize:重新设置size的值
d = { 1,2,3,4,5 };
d.resize(3);
//d="1 2 3"
d = { 1,2,3,4,5 };
d.resize(10);
//d="1 2 3 4 5 0 0 0 0 0"
d = { 1,2,3,4,5 };
d.resize(10, 8);
//用8替换多余的部分
//insert:插入函数
d = { 1,2,3 };
d.insert(d.begin(), 6);
//在位置前插入6
//d="6 1 2 3"
d = { 1,2,3 };
d.insert(d.begin() + 1, 3, 6);
//在位置前插入3个6
//d="1 6 6 6 2 3"
d = { 1,2,3 };
d1 = { 6,6,6 };
d.insert(d.begin() + 2, d1.begin(), d1.end());
//在位置前插入区间元素
//d="1 2 6 6 6 3"
//emplace:插入函数
//相比于push_back和insert,emplace速度更快
d = { 1,2,3 };
d.emplace(d.begin(), 0);
//在位置之前插入0
//相当于d.insert(d.begin(),0);
//d="0 1 2 3"
d = { 1,2,3 };
d.emplace_front(0);
//在头部插入0
//相当于d.push_front(0);
//d="0 1 2 3"
d = { 1,2,3 };
d.emplace_back(4);
//在末尾插入元素4
//相当于d.push_back(4);
//d="1 2 3 4"
//erase:删除元素
d = { 1,2,3 };
auto it = d.erase(d.begin() + 1);
//删除位置上的元素,返回指向下一个元素的迭代器
//d="1 3"
//*it = 3
d = { 1,2,3,4,5 };
it = d.erase(d.begin() + 1, d.end() - 1);
//删除区间元素,返回指向下一个元素的迭代器
//d="1 5"
//*it = 5
return 0;
}
stack
- 构造函数:
#include <iostream>
#include <stack>
using std::stack;
int main()
{
stack<int> st;
stack<char> stch;
stack<std::string> ststr;
stack<int> st2(st);
}
- 常用函数:
点击查看代码
#include <iostream>
#include <stack>
using std::stack;
int main()
{
stack<int> st;
//push:在栈顶插入元素
st.push(1);
st.push(2);
st.push(3);
st.push(4);
st.push(5);
//st="1 2 3 4 5"
//emplace:同上
st.emplace(6);
st.emplace(7);
//pop:弹出栈顶元素
st.pop();
st.pop();
st.pop();
st.pop();
st.pop();
st.pop();
st.pop();
//size:返回元素个数
int result = st.size();
//result = 0
//empty:判断是否为空
result = st.empty();
//result = 1
//swap:交换函数
stack<int> st1;
st1.push(1);
st1.push(2);
st1.push(3);
stack<int> st2;
st2.push(3);
st2.push(2);
st2.push(1);
st1.swap(st2);
//top:返回栈顶元素
result = st2.top();
//result = 3
return 0;
}
queue
- 构造函数:
#include <iostream>
#include <queue>
using std::queue;
int main()
{
queue<int> q;
queue<std::string> qstr;
queue<int> q1(q);
}
- 常用函数:
点击查看代码
#include <iostream>
#include <queue>
using std::queue;
int main()
{
queue<int> q;
//push:队尾插入元素
q.push(1);
q.push(2);
q.push(3);
q.push(4);
//q="1 2 3 4"
//emplace:同上
q.emplace(5);
//q="1 2 3 4 5"
//front:返回队列头部元素
int result = q.front();
//result = 1
//back:返回队列尾部元素
result = q.back();
//result = 5
//size:返回元素个数
result = q.size();
//result = 5
//pop:弹出队列头部元素
q.pop();
q.pop();
q.pop();
//q="4 5"
//empty:判断队列是否为空
result = q.empty();
//result = 0
//swap:交换函数
queue<int> q1;
q.swap(q1);
return 0;
}
priority_queue
优先队列:在队列的基础上将内部进行排序, 默认降序, 只能访问头部
头文件还是'queue'
- 构造函数:
#include <iostream>
#include <queue>
using std::priority_queue;
int main()
{
priority_queue<int> p1;
priority_queue<std::string> p2;
priority_queue<std::string> p3(p2);
}
-
迭代器:
单向迭代器:不支持随机访问,不支持双向遍历,只支持单向遍历 -
常用函数:
点击查看代码
#include <iostream>
#include <queue>
using std::priority_queue;
int main()
{
priority_queue<int> p1;
//push:尾插函数
p1.push(2);
p1.push(0);
p1.push(1);
//默认为降序
//p1={2,1,0}
//top:返回队头元素(最大值元素)
int result = p1.top();
//result=2
//pop:头删函数
p1.pop();
result = p1.top();
//result=1
//p1={1,0}
//emplace:尾插函数
p1.emplace(-1);
//p1={1,0,-1}
//size:返回元素个数
result = p1.size();
//result=3
//empty:判断是否为空
result = p1.empty();
//result=0
//swap:交换函数
priority_queue<int> p2;
p2.push(4);
p2.push(5);
p2.push(3);
//p1={1,0,-1}
//p2={5,4,3}
p1.swap(p2);
//p1={5,4,3}
//p2={1,0,-1}
//测试代码:
//while (!p2.empty())
//{
// std::cout << p2.top() << " ";
// p2.pop();
//}
//std::cout << std::endl;
//std::cout << result << std::endl;
return 0;
}
list
双向循环链表
- 构造函数:
#include <iostream>
#include <list>
using std::list;
int main()
{
list<int> list1;
list<std::string> list2;
list<int> list3(10);
list<int> list4(10, 2);//10个2
list<int> list5{ 1,2,3,4,5 };
list<int> list6 = { 1,2,3,4,5 };
list<int> list7(list6);
list<int> list8(list6.begin(), list6.end());
}
- 迭代器:
双向迭代器:不支持随机访问
#include <iostream>
#include <list>
using std::list;
int main()
{
list<int> list1={ 1, 2, 3, 4, 5 };
list<int>::iterator it = list1.begin();
it++;//valid
//双向迭代器
//不支持随机访问
//it = it + 1;//invalid
//it = it + 2;//invalid
return 0;
}
- 常用函数:
点击查看代码
#include <iostream>
#include <list>
using std::list;
int main()
{
//不支持下标 [] 和 at 函数随机访问容器内元素, 只能通过迭代器访问
//assign:赋值函数
list<int> list1 = { 1, 2, 3, 4, 5 };
list1.assign(2, 3);//将2个3赋值给list1
//list1={ 3, 3 };
list1 = { 1,2,3,4,5 };
list<int> list2;
list2.assign(list1.begin(), list1.end());
//list2={ 1,2,3,4,5 };
//swap:交换函数
list1 = { 1,2,3 };
list2 = { 4,5,6 };
list1.swap(list2);
//list1={ 4,5,6 };
//list2={ 1,2,3 };
//push_front:在头部插入元素
list1 = { 1,2,3 };
list1.push_front(0);
//list1={ 0,1,2,3 };
//pop_front:删除头部元素
list1 = { 1,2,3 };
list1.pop_front();
//list1={ 2,3 };
//push_back:在尾部插入元素
list1 = { 1,2,3 };
list1.push_back(4);
//list1={ 1,2,3,4 };
//pop_back:删除尾部元素
list1 = { 1,2,3 };
list1.pop_back();
//list1={ 1,2 };
//front:返回第一个元素
list1 = { 1,2,3 };
int result = list1.front();
//result=1;
//back:返回最后一个元素
list1 = { 1,2,3 };
result = list1.back();
//result=3;
//clear:清空所有元素
list1 = { 1,2,3 };
list1.clear();
//list1={ };
//empty:判断是否为空
list1 = { 1,2,3 };
result = list1.empty();
//result=0;
//size:返回元素个数
list1 = { 1,2,3 };
result = list1.size();
//result=3;
//resize:重新指定大小
list1 = { 1,2,3 };
list1.resize(5);
//list1={ 1,2,3,0,0 };
list1 = { 1,2,3 };
list1.resize(5, 4);
//list1={ 1,2,3,4,4 };
list1 = { 1,2,3 };
list1.resize(1);
//list1={ 1 };
//insert:插入元素
list1 = { 1,2,3 };
list1.insert(list1.begin(), 0);
//list1={ 0,1,2,3 };
list1 = { 1,2,3 };
list1.insert(list1.begin(), 2, 0);
//list1={ 0,0,1,2,3 };
list1 = { 1,2,3 };
list1.insert(list1.begin(), list1.begin(), list1.end());
//list1={ 1,2,3,1,2,3 };
//emplace:原地构造元素
list1 = { 1,2,3 };
list1.emplace(list1.begin(), 0);
//list1={ 0,1,2,3 };
//emplace_back:在尾部构造元素
list1 = { 1,2,3 };
list1.emplace_back(0);
//list1={ 1,2,3,0 };
//emplace_front:在头部构造元素
list1 = { 1,2,3 };
list1.emplace_front(0);
//list1={ 0,1,2,3 };
//merge:合并两个有序链表(list1和list2必须为升序),合并后为升序
list1 = { 1,3,5 };
list2 = { 2,4,6 };
list1.merge(list2);
//list1={ 1,2,3,4,5,6 };
//list2={ }
//(list1和list2必须为降序),合并后为降序
list1 = { 5,3,1 };
list2 = { 6,4,2 };
list1.merge(list2, std::greater<int>());//std::greater<int>()是一个比较函数
//splice:拼接函数
list1 = { 1,3,5 };
list2 = { 2,4,6 };
list1.splice(list1.begin(),list2);
//将list2拼接到list1.begin()处
//list1={ 2,4,6,1,3,5 };
//list2={ };
list1 = { 1,3,5 };
list2 = { 2,4,6 };
list1.splice(list1.begin(), list2,list2.begin());
//将list2.begin()处的元素拼接到list1.begin()处
//list1={ 2,1,3,5 };
//list2={ 4,6 };
list1 = { 1,3,5 };
list2 = { 2,4,6 };
list1.splice(list1.begin(), list2, ++list2.begin());
//将list2.begin()+1处的元素拼接到list1.begin()处
//list1={ 4,1,3,5 };
//list2={ 2,6 };
list1 = { 1,3,5 };
list2 = { 2,4,6 };
list1.splice(list1.begin(), list2, list2.begin(), list2.end());
//将区间元素拼接到list1.begin()处
//list1={ 2,4,6,1,3,5 };
//list2={ };
//insert / merge / splice 三个插入函数的区别:
//insert函数:将容器b的内容复制插入到容器a中
//merge函数:在使用之前两个容器必须具有相同的顺序,将容器b的内容移动插入到容器a中, 将容器b中插入的内容删除
//splice函数:将容器b的内容移动插入到容器a中, 将容器b中插入的内容删除
//erase:删除函数
list1 = { 1,2,3 };
list1.erase(list1.begin());
//删除指定元素
//list1={ 2,3 };
list1 = { 1,2,3 };
list1.erase(list1.begin(), --list1.end());
//删除指定区间
//list1={ 3 };
//remove:删除函数
list1 = { 1,2,2,2,3 };
list1.remove(2);
//删除所有的2
//list1={ 1,3 };
//unique:排重函数
list1 = { 1,2,2,2,3,3,4,4,5,6,3,3 };
list1.unique();
//排除相邻的相同元素,只保留一个
//list1={ 1,2,3,4,5,6,3 };
//erase / remove / unique 三个删除函数的区别
//erase函数:是通过迭代器查找到元素之后,进行删除
//remove函数:是通过值查到元素之后,进行删除
//unique函数:只将相邻的相同元素删除
//reverse:翻转函数
list1 = { 1,2,3,4,5 };
list1.reverse();
//list1={ 5,4,3,2,1 };
//sort:排序函数
list1 = { 4,2,6,3,5,1 };
list1.sort();
//升序排序
//list1={ 1,2,3,4,5,6 }
list1 = { 4,2,6,3,5,1 };
list1.sort(std::greater<int>());
//降序排序
//list1={ 6,5,4,3,2,1 };
//sort和unique函数结合
//达到将容器中所有相同元素(不是相邻)删除的效果
list1 = { 1,2,2,2,3,3,4,4,5,6,3,3 };
list1.sort();
list1.unique();
//list1={ 1,2,3,4,5,6 };
return 0;
}
forward_list
单链表:将list容器的末端封住,不能直接的访问和操作
- 构造函数:
#include <iostream>
#include <forward_list>
using std::forward_list;
int main()
{
forward_list<int> f1;
forward_list<std::string> f2;
forward_list<int> f3(10);//10个元素,每个元素都为0
forward_list<int> f4(10, 5);//10个元素,每个元素都为5
forward_list<int> f5 = { 1,2,3,4,5 };
forward_list<int> f6(f5);
forward_list<int> f7(f5.begin(), f5.end());
}
-
迭代器:
单向迭代器:不支持随机访问,不支持双向遍历,只能单向遍历 -
常用函数:
点击查看代码
#include <iostream>
#include <forward_list>
using std::forward_list;
bool Greater3(int val)
{
return val > 3;
}
int main()
{
//assign:赋值函数
forward_list<int> f1;
f1.assign(2, 3);
//将2个3赋值给f1
//f1={3,3}
forward_list<int> f2 = { 1,2,3 };
f1.assign(f2.begin(), f2.end());
//将区间内的元素赋值给f1
//f1={1,2,3}
//swap:交换函数
f1 = { 1,2,3 };
f2 = { 4,5,6 };
f1.swap(f2);
//f1={4,5,6}
//f2={1,2,3}
//push_front:头插函数
f1 = { 1,2,3 };
f1.push_front(0);
//f1={0,1,2,3}
//pop_front:头删函数
f1 = { 1,2,3 };
f1.pop_front();
//f1={2,3}
//front:返回头部元素
f1 = { 1,2,3 };
int result = f1.front();
//result=1
//clear:清空容器
f1 = { 1,2,3 };
f1.clear();
//f1={}
//empty:判断是否为空
result = f1.empty();
//result=1
//resize:设置size
f1 = { 1,2,3,4,5 };
f1.resize(3);
//f1={1,2,3}
f1 = { 1,2,3,4,5 };
f1.resize(10);
//f1={1,2,3,4,5,0,0,0,0,0}
f1 = { 1,2,3,4,5 };
f1.resize(10, 8);
//f1={1,2,3,4,5,8,8,8,8,8}
//insert_after:插入函数
f1 = { 1,2,3 };
f1.insert_after(f1.begin(), 0);
//在位置后面插入元素
//f1={1,0,2,3}
f1 = { 1,2,3 };
f1.insert_after(f1.begin(), 5, 0);
//在位置后面插入5个元素0
//f1={1,0,0,0,0,0,2,3}
f1 = { 1,2,3 };
f2 = { 4,5,6 };
f1.insert_after(f1.begin(), f2.begin(), f2.end());
//在f1位置后面插入f2区间的元素
//f1={1,4,5,6,2,3}
//emplace:插入函数
f1 = { 1,2,3 };
f1.emplace_front();
//在头部插入一个元素,默认为0
//f1={0,1,2,3}
f1 = { 1,2,3 };
f1.emplace_front(1);
//在头部插入元素1
//f1={1,1,2,3}
f1 = { 1,2,3 };
f1.emplace_after(f1.begin(), 0);
//f1={1,0,2,3}
//merge:合并函数
f1 = { 1,2,3 };
f2 = { 2,4,6 };
f1.merge(f2);
//f1,f2必须有序,合并后仍然有序(默认为升序)
//将f2的元素转移到f1
//f1={1,2,2,3,4,6}
//f2={}
f1 = { 3,2,1 };
f2 = { 6,4,2 };
f1.merge(f2, std::greater<int>());
//为降序
//f1={6,4,3,2,2,1}
//f2={}
//splice_after:拼接函数
f1 = { 1,2,3 };
f2 = { 4,5,6 };
f1.splice_after(f1.begin(), f2);
//将f2拼接到f1位置之后
//f1={1,4,5,6,2,3}
//f2={}
f1 = { 1,2,3 };
f2 = { 4,5,6 };
f1.splice_after(f1.begin(), f2, f2.begin());
//将f2所指元素转移到f1的位置之后
//f1={1,5,2,3}
//f2={4,6}
f1 = { 1,2,3 };
f2 = { 4,5,6 };
f1.splice_after(f1.begin(), f2, f2.begin(), f2.end());
//将f2区间内元素转移到f1的位置之后(保留f2区间内的第一个元素)
//f1={1,5,6,3}
//f2={4}
//erase_after:删除函数
f1 = { 1,2,3 };
f1.erase_after(f1.begin());
//删除指向位置之后的元素
//f1={1,3}
f1 = { 1,2,3 };
f1.erase_after(f1.begin(), f1.end());
//删除区间内的元素(保留区间内的第一个元素)
//f1={1}
//remove:移除函数
f1 = { 1,2,2,2,3 };
f1.remove(2);
//删除所有值为2的元素
//f1={1,3}
//remove_if:移除函数
f1 = { 1,2,3,4,5 };
f1.remove_if(Greater3);
//删除大于3的元素
//f1={1,2,3}
//unique:排重函数
f1 = { 1,1,2,2,2,3,2 };
f1.unique();
//排除相邻重复元素
//f1={1,2,3,2}
//reverse:反转函数
f1 = { 1,2,3 };
f1.reverse();
//f1={3,2,1}
//sort:排序函数
f1 = { 1,4,3,5,2 };
f1.sort();
//默认以升序排序
//f1={1,2,3,4,5}
f1 = { 1,4,3,5,2 };
f1.sort(std::greater<int>());
//以降序排序
//f1={5,4,3,2,1}
//测试代码:
//std::cout << result << std::endl;
//for (auto x : f1)
//{
// std::cout << x << " ";
//}
//std::cout << std::endl;
//for (auto x : f2)
//{
// std::cout << x << " ";
//}
return 0;
}
pair
pair将一对值(T1和T2)组合成一个值,这一对值可以具有不同的数据类型
- 构造函数:
#include <iostream>
#include <utility>
int main()
{
std::pair<int, int>p1;
std::pair<std::string, int> p2("Tom", 20);
std::pair<std::string, int> p3 = { "Tom", 20 };
std::pair<std::string, int> p4(p3);
std::pair<std::string, int> p5 = std::make_pair("Jerry", 10);
auto p6 = std::make_pair("Jerry", 10);
}
- 常用函数:
点击查看代码
#include <iostream>
#include <utility>
#include <string>
int main()
{
//first:返回第一个内容
//second:返回第二个内容
std::pair<std::string, int> p1 = { "Tom", 20 };
std::cout << "name: " << p1.first << " age: " << p1.second << std::endl;
//swap:交换函数
std::pair<std::string, int> p2("Jerry", 10);
std::cout << "name: " << p1.first << " age: " << p1.second << std::endl;
std::cout << "name: " << p2.first << " age: " << p2.second << std::endl;
std::cout << "-------------------------" << std::endl;
swap(p1, p2);
std::cout << "name: " << p1.first << " age: " << p1.second << std::endl;
std::cout << "name: " << p2.first << " age: " << p2.second << std::endl;
return 0;
}
set
根据特定的排序标准,自动将元素进行排序
- set和multiset的区别:
set: 容器中每种元素只能存在一个
multiset: 容器中的元素可以重复
set和multiset为双向迭代器,迭代器只能++或-- - 构造函数:
#include <iostream>
#include <set>
using std::set;
using std::multiset;
int main()
{
set<int> s1;
multiset<int> s2;
set<std::string> s3;
set<int> s4 = { 1,2,3,4,5 };
set<int> s5(s4);
set<int> s6(s4.begin(), s4.end());
set<int, std::greater<int>> s7;//排序准则为降序
}
- 利用仿函数可以指定set容器的排序规则:
点击查看代码
#include <iostream>
#include <set>
class MyCompare
{
public:
bool operator()(int v1, int v2)const//必须要加const限定符
{
return v1 > v2;
}
MyCompare(){ }
};
int main()
{
std::set<int,MyCompare> s1;//需要在插入之前指定排序顺序
s1.insert(4);
s1.insert(1);
s1.insert(3);
s1.insert(2);
s1.insert(5);
for (std::set<int,MyCompare>::iterator it = s1.begin(); it != s1.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
- set存放自定义数据类型:
点击查看代码
#include <iostream>
#include <set>
#include <string>
class Person
{
public:
std::string m_name;
int m_age;
public:
Person(std::string name, int age);
};
Person::Person(std::string name, int age)
{
m_name = name;
m_age = age;
}
class ComparePerson
{
public:
bool operator()(const Person& p1, const Person& p2)const//必须要加3个const限定符
{
//按照年龄进行降序排序
return p1.m_age > p2.m_age;
}
};
int main()
{
Person p1("p1", 24);
Person p2("p2", 23);
Person p3("p3", 21);
Person p4("p4", 23);
Person p5("p5", 27);
Person p6("p6", 13);
std::multiset<Person, ComparePerson> s = {p1,p2,p3,p4,p5,p6};
for (auto it = s.begin(); it != s.end(); it++)
{
std::cout << "name:" << it->m_name << " age:" << it->m_age << std::endl;
}
}
- 常用函数:
点击查看代码
#include <iostream>
#include <set>
#include <utility>
using std::set;
using std::multiset;
void PrintSet(set<int>&s1)
{
for (auto it = s1.begin(); it != s1.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
void PrintMultiset(multiset<int>& s1)
{
for (auto it = s1.begin(); it != s1.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
int main()
{
set<int> s0 = { 3,3,4,5,2,1 };
multiset<int> s = { 3,3,4,5,2,1 };
//PrintSet(s0);
//PrintMultiset(s);
//s1={1,2,3,4,5}
//s2={1,2,3,3,4,5}
//swap:交换函数
set<int> s1 = { 3,2,1 };
set<int> s2 = { 5,4,3,2,1 };
s1.swap(s2);
//交换之前
//s1={1,2,3}
//s2={1,2,3,4,5}
//交换之后
//s1={1,2,3,4,5}
//s2={1,2,3}
//clear:清空容器
s1.clear();
//s1={ }
//empty:判断是否为空
int result = s1.empty();
//result=1
//size:返回容器元素个数
s1 = { 3,2,1 };
result = s1.size();
//insert:插入函数
//set容器只有insert这一个插入函数
s1 = { 4,3,2,1 };
s1.insert(0);
s1.insert(5);
s1.insert(3);//3为重复元素,此语句不执行
//s1={0,1,2,3,4,5}
s1 = { 4,3,2,1 };
s1.insert(s1.begin(), 5);
//与上面没什么区别
s1 = { 3,2,1 };
s2 = { 5,1,4,0 };
s1.insert(s2.begin(), s2.end());
//插入s2区间的元素
//s1={0,1,2,3,4,5}
//s2={0,4,5}
//emplace:插入函数
s1 = { 4,3,2,1 };
s1.emplace(0);
//s1={0,1,2,3,4}
//erase:删除函数
s1 = { 5,4,3,2,1 };
s1.erase(2);
//将值为2的元素删除
//s1={1,3,4,5}
s1 = { 5,4,3,2,1 };
s1.erase(s1.begin());
//删除排序后迭代器所指向的元素
//s1={2,3,4,5}
s1 = { 5,4,3,2,1 };
s1.erase(s1.begin(), s1.end());
//删除区间元素
//s={ }
//count:返回元素个数
//set容器只有0或1
s1 = { 1,1,2,3,4 };
result = s1.count(1);
//result=1
result = s1.count(2);
//result=1
result = s1.count(5);
//result=0
//multiset容器有超过1的值
multiset<int> s3 = { 1,2,2,3,3,3,4,4,4,4 };
result = s3.count(0);
//result=0
result = s3.count(3);
//result=3
result = s3.count(4);
//result=4
//find:查找函数
s1 = { 5,4,2,1 };
auto it = s1.find(5);
//若找到,则返回指向该元素的迭代器
//若未找到,则返回迭代器end()
//*it=5
it = s1.find(2);
//*it=2
it = s1.find(6);
if (it == s1.end())
{
std::cout << "未找到" << std::endl;
}
//未找到
//lower_bound:查找函数
s1 = { 5,2,1 };
it = s1.lower_bound(2);
//返回第一个>=2的元素的迭代器
//*it=2
it = s1.lower_bound(3);
//返回第一个>=3的元素的迭代器
//*it=5
//upper_bound:查找函数
s1 = { 5,2,1 };
it = s1.upper_bound(2);
//返回第一个>2的元素的迭代器
//*it=5
it = s1.upper_bound(3);
//返回第一个>3的元素的迭代器
//*it=5
//equal_range:查找函数
s1 = { 5,3,2,1 };
std::pair<set<int>::iterator, set<int>::iterator> p;
p = s1.equal_range(3);
//返回pair容器:(s1.lower_bound(3),s1.upper_bound(3))
//pair(指向3的迭代器,指向5的迭代器)
std::cout << "s1.lower_bound(3):" << *p.first << " s1.upper_bound(3):" << *p.second << std::endl;
//s1.lower_bound(3):3
//s1.upper_bound(3):5
//测试代码:
//std::cout << *it << std::endl;
//std::cout << result << std::endl;
//PrintSet(s1);
//PrintSet(s2);
return 0;
}
map
①map容器每个元素类型为pair
②pair第一部分为键(key)
,第二部分为值(value)
③默认通过key进行升序排序
④map和multimap为双向迭代器
- map和multimap:
map:容器中key只能存在一个,支持随机访问
multimap:容器中key可以存在多个,不支持随机访问 - 构造函数:
#include <iostream>
#include <map>
using std::map;
using std::multimap;
int main()
{
map<int, int> m1;
multimap<int, int> m2;
map<int, std::string> m3;
map<int, std::string> m4 = { {1,"aaa"},{2,"bbb"},{3,"ccc"} };
map<int, std::string> m5(m4);
map<int, std::string> m6(m4.begin(), m4.end());
map<int, std::string, std::greater<int>> m7;//排序规则为降序
//map<int, std::string, op> m8;//排序规则为op
}
- 常用函数:
点击查看代码
#include <iostream>
#include <map>
using std::map;
using std::multimap;
void PrintMap(map<int, std::string>& m)
{
for (auto it = m.begin(); it != m.end(); it++)
{
std::cout << "key:" << it->first << " value:" << it->second << std::endl;
}
std::cout << std::endl;
}
void PrintMultiMap(multimap<int, std::string>& m)
{
for (auto it = m.begin(); it != m.end(); it++)
{
std::cout << "key:" << it->first << " value:" << it->second << std::endl;
}
std::cout << std::endl;
}
int main()
{
//下标/at(只有map可以随机访问)
map<int, std::string> m = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
std::cout << m[1];//valid
std::cout << m.at(3);
multimap<int, std::string> m0 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
//std::cout << m0[1];//invalid
//std::cout << m0.at(3);//invalid
//下标不一定是数字,只适用于map
map<std::string, int> mm1 = { { "bbb",2 }, { "ccc",3 } ,{ "aaa", 1 } };
std::cout << mm1["bbb"];//valid
std::cout << mm1["ccc"];//valid
std::cout << std::endl;
multimap<std::string, int> mm2 = { { "bbb",2 }, { "ccc",3 } ,{ "aaa", 1 } };
//std::cout << mm2["bbb"];//invalid
//std::cout << mm2["ccc"];//invalid
//swap:交换函数
map<int, std::string> m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
map<int, std::string> m2 = { {5,"eee"},{4,"ddd"},{6,"fff"} };
PrintMap(m1);
PrintMap(m2);
std::cout << "----------------" << std::endl;
m1.swap(m2);
PrintMap(m1);
PrintMap(m2);
//clear:清空容器
m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
m1.clear();
//m1={ }
//empty:判断容器是否为空
int result = m1.empty();
//result=1
//size:返回容器元素个数
m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
result = m1.size();
//result=3
//insert:插入函数
m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
m1.insert({ 4,"ddd" });
m1.insert(std::pair<int, std::string>(5, "eee"));
m1.insert(std::make_pair(6, "fff"));
m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
m1.insert(m1.begin(), { 4,"ddd" });
//同上
m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
m2 = { {5,"eee"},{4,"ddd"},{6,"fff"} };
m1.insert(m2.begin(), m2.end());
//插入区间所有元素
//emplace:插入函数
m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
m1.emplace(std::pair<int, std::string>(4, "ddd"));//valid
m1.emplace(std::pair<int, std::string>{5, "eee"});//valid
//m1.emplace({ 4,"ddd" });//invalid
//erase:删除函数
m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
m1.erase(2);
//删除key为2的元素
m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
m1.erase(m1.begin());
//删除指向的元素(删除了key1)
m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
m1.erase(m1.begin(), m1.end());
//删除区间内所有元素
//count:计算相同key值的个数
//对于map:只有0或1
m1 = { {2,"bbb"}, {2,"ccc"},{2,"aaa"} };
result = m1.count(2);
//result=1
result = m1.count(3);
//result=0
//对于multimap:有超过1的值
m0 = { {2,"bbb"}, {2,"ccc"},{2,"aaa"} };
result = m0.count(2);
//result=3
result = m0.count(3);
//result=0
//find:查找函数
m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
auto it = m1.find(3);
//返回指向key值为3的迭代器
//若没找到,则返回迭代器end()
//lower_bound:查找函数
m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
it = m1.lower_bound(2);
//返回key值>=2的第一个元素的迭代器
//it->first=2 it->second=bbb
//upper_bound:查找函数
m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
it = m1.upper_bound(2);
//返回key值>2的第一个元素的迭代器
//it->first=3 it->second=ccc
//equal_range:查找函数
m1 = { {2,"bbb"}, {3,"ccc"},{1,"aaa"} };
std::pair<map<int, std::string>::iterator, map<int, std::string>::iterator> i;
i = m1.equal_range(2);
//返回 pair 容器: [m.lower_bound(2), m.upper_bound(2)]
std::cout << "m.lower_bound(2)的key:" << i.first->first << " m.lower_bound(2)的value:" << i.first->second << std::endl;
std::cout << "m.upper_bound(2)的key:" << i.second->first << " m.upper_bound(2)的value:" << i.second->second << std::endl;
//返回pair{指向{2,"bbb"}的迭代器, 指向{3,"ccc"}的迭代器}
//m.lower_bound(2)的key:2 m.lower_bound(2)的value:bbb
//m.upper_bound(2)的key:3 m.upper_bound(2)的value:ccc
//测试代码:
//std::cout << "key:" << it->first << " value:" << it->second << std::endl;
//std::cout << result << std::endl;
//PrintMap(m1);
//std::cout << "-------\n";
//PrintMultiMap(m0);
return 0;
}
函数对象
①函数对象(仿函数)是一个类,而不是函数
②函数对象(仿函数)重载了'()'操作符使得它可以像普通函数一样使用
总结:函数对象实质上是一个实现了operator()操作运算符的类
- 特点:
1.函数对象可以像普通函数一样调用
2.可以存储附加数据
3.函数对象可以作为传递参数
点击查看代码
#include <iostream>
//1.函数对象可以像普通函数一样调用
class MyAdd
{
public:
int operator()(int v1, int v2)
{
return v1 + v2;
}
};
void test01()
{
MyAdd myadd;
std::cout << myadd(10, 10) << std::endl;
}
//2.可以存储附加数据
class MyPrint
{
public:
int count;
public:
MyPrint()
{
count = 0;
}
void operator()(std::string s)
{
std::cout << s << std::endl;
count++;
}
};
void test02()
{
MyPrint myprint;
myprint("666");
myprint("666");
myprint("666");
myprint("666");
myprint("666");
myprint("666");
std::cout << myprint.count << std::endl;
}
//3.函数对象可以作为传递参数
void doPrint(MyPrint& mp, std::string s)
{
mp(s);
}
void test03()
{
MyPrint myprint;
doPrint(myprint, "Hello C++");
}
int main()
{
test01();
test02();
test03();
return 0;
}
谓词
- 定义:返回bool类型的仿函数
一元谓词:operator()接受一个参数
点击查看代码
#include <iostream>
#include <vector>
#include <algorithm>
class GreaterFive
{
public:
bool operator()(int val)
{
return val > 5;
}
};
int main()
{
std::vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
auto it = std::find_if(v.begin(), v.end(), GreaterFive());
if (it != v.end())
{
std::cout << "找到了" << std::endl;
}
else
{
std::cout << "没找到" << std::endl;
}
}
二元谓词:operator()接受两个参数
点击查看代码
#include <iostream>
#include <vector>
#include <algorithm>
class MyCompare
{
public:
bool operator()(int v1, int v2)
{
return v1 > v2;
}
};
int main()
{
std::vector<int> v;
v.push_back(10);
v.push_back(40);
v.push_back(20);
v.push_back(30);
v.push_back(50);
//默认从小到大
std::sort(v.begin(), v.end());
for (auto it = v.begin(); it != v.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
//从大到小
std::sort(v.begin(), v.end(), MyCompare());
for (auto it = v.begin(); it != v.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
内建函数对象
- 定义:STL提供的仿函数
需要加头文件‘functional’ - 分类:
①算数类函数对象(negate是一元运算,其他都是二元运算)
点击查看代码
#include <iostream>
#include <functional>
int main()
{
//plus:加法仿函数
std::plus<int> p;
int result = p(10, 20);
//result=30
//minus:减法仿函数(左-右)
std::minus<int> m;
result = m(20,10);
//result=10
//multiplies:乘法仿函数
std::multiplies<int> mu;
result = mu(10, 10);
//result=100
//divides:除法仿函数
std::divides<double> d;
result = d(10, 5);
//result=2
//modulus:取模仿函数
std::modulus<int> mo;
result = mo(10, 3);
//result=1
//negate:取反仿函数
std::negate<int> ne;
result = ne(10);
//result=-10
//测试代码
//std::cout << result << std::endl;
return 0;
}
②关系运算类函数对象(都是二元运算)
点击查看代码
#include <iostream>
#include <functional>
int main()
{
//equal_to:等于
std::equal_to<int> eq;
int result = eq(10, 10);
//result=1
//not_equal_to:不等于
std::not_equal_to<int> neq;
result = neq(10, 10);
//result=0
//greater:大于
std::greater<int> gr;
result = gr(2, 1);
//result=1
//greater_equal:大于等于
std::greater_equal<int> ge;
result = ge(2, 2);
//result=1
//less:小于
std::less<int> l;
result = l(1, 2);
//result=1
//less_equal:小于等于
std::less_equal<int> le;
result = le(2, 2);
//result=1
//测试代码
//std::cout << result << std::endl;
return 0;
}
③逻辑运算类函数对象(not为一元运算,其他为二元运算)
点击查看代码
#include <iostream>
#include <functional>
int main()
{
//logical_and:逻辑与(有假即假,全真才真)
std::logical_and<int> an;
int result = an(1, 0);
//result=0
//logical_or:逻辑或(有真即真,全假才假)
std::logical_or<int> o;
result = o(1, 0);
//result=1
//logical_not:逻辑非
std::logical_not<bool> no;
result = no(true);
//result=0
//测试代码:
std::cout << result << std::endl;
return 0;
}
使用内建函数对象,改变排序规则:
点击查看代码
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> v;
v.push_back(10);
v.push_back(30);
v.push_back(20);
v.push_back(50);
v.push_back(40);
for (auto it = v.begin(); it != v.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
std::cout << "排序后:" << std::endl;
std::sort(v.begin(), v.end(), std::greater<int>());
for (auto it = v.begin(); it != v.end(); it++)
{
std::cout << *it << " ";
}
return 0;
}
STL算法
for_each
:遍历容器
for_each(iterator beg, iterator end, _func);
beg 开始迭代器
end 结束迭代器
_func 函数或者函数对象
需要写一个普通函数或函数对象
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
void Print01(int v)
{
std::cout << v;
}
class Print02
{
public:
void operator()(int v)
{
std::cout << v;
}
};
int main()
{
std::vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
std::for_each(v.begin(), v.end(), Print01);//普通函数直接传入
std::cout << std::endl;
std::for_each(v.begin(), v.end(), Print02());//函数对象(仿函数)需要加括号
return 0;
}
transform
:搬运容器到另一个容器中
transform(iterator beg1, iterator end1, iterator beg2, _func);
beg1 源容器开始迭代器
end1 源容器结束迭代器
beg2 目标容器开始迭代器
_func 函数或者函数对象
搬运的目标容器必须要提前开辟空间,否则无法正常搬运
点击查看代码
#include <iostream>
#include <vector>
#include <algorithm>
class MyTransform
{
public:
int operator()(int v)
{
//return v;
return v + 100;//可以对值进行修改
}
};
class MyPrint
{
public:
void operator()(int v)
{
std::cout << v << " ";
}
};
int main()
{
std::vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
std::vector<int> v2;
v2.resize(v.size());//必须提前开辟空间
std::transform(v.begin(), v.end(), v2.begin(),MyTransform());
std::for_each(v2.begin(), v2.end(), MyPrint());
return 0;
}
find
:查找函数
find(iterator beg, iterator end, value);
beg 开始迭代器
end 结束迭代器
value 查找的元素
按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置
点击查看代码
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
auto it = std::find(v.begin(), v.end(), 6);
if (it == v.end())
{
std::cout << "没有找到\n";
}
else
{
std::cout << "找到" << *it << std::endl;
}
}
自定义数据类型时需要重载==运算符
点击查看代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
class Person
{
public:
std::string m_Name;
int m_Age;
Person(std::string name, int age)
{
m_Name = name;
m_Age = age;
}
bool operator==(const Person& p)//必须要重载==运算符
{
if (m_Name == p.m_Name && m_Age == p.m_Age)
{
return true;
}
else
{
return false;
}
}
};
int main()
{
std::vector<Person> v;
Person p1("p1", 1);
Person p2("p2", 2);
Person p3("p3", 3);
Person p4("p4", 4);
Person p5("p5", 5);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
Person x("p2", 2);
auto it = std::find(v.begin(), v.end(), x);
if (it == v.end())
{
std::cout << "没有找到\n";
}
else
{
std::cout << "找到:" << "name:" << it->m_Name << " age:" << it->m_Age << std::endl;
}
}
find_if
:按指定规则查找元素
find_if(iterator beg, iterator end, _Pred);
beg 开始迭代器
end 结束迭代器
_Pred 函数或者谓词
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
class GreaterTow
{
public:
bool operator()(int v)
{
return v > 2;
}
};
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
auto it = std::find_if(v.begin(), v.end(), GreaterTow());
std::cout << *it << std::endl;
return 0;
}
自定义数据类型:
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
class Person
{
public:
std::string m_Name;
int m_Age;
Person(std::string name,int age)
{
m_Name = name;
m_Age = age;
}
};
class MyCompare
{
public:
bool operator()(Person& v)
{
return v.m_Age > 30;
}
};
int main()
{
Person p1("p1", 10);
Person p2("p2", 20);
Person p3("p3", 30);
Person p4("p4", 40);
Person p5("p5", 50);
std::vector<Person> v;
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
auto it = std::find_if(v.begin(), v.end(), MyCompare());
std::cout << "name:" << it->m_Name << " age:" << it->m_Age << std::endl;
return 0;
}
adjacent_find
:查找相邻且重复的元素
adjacent_find(iterator beg, iterator end);
beg 开始迭代器
end 结束迭代器
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
int main()
{
std::vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(2);
v.push_back(0);
v.push_back(1);
v.push_back(0);
auto it = std::adjacent_find(v.begin(), v.end());
std::cout << *it << std::endl;
//*it=2
return 0;
}
binary_search
:二分查找
bool binary_search(iterator beg, iterator end, value);
beg 开始迭代器
end 结束迭代器
value 查找的元素
必须在有序序列中查找指定元素value,找到返回true,否则返回false
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
int main()
{
std::vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
int result = std::binary_search(v.begin(), v.end(), 6);
std::cout << result << std::endl;
//result=1
return 0;
}
count
:统计相同元素出现次数
count(iterator beg, iterator end, value);
beg 开始迭代器
end 结束迭代器
value 统计的元素
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
int main()
{
std::vector<int> v;
v.push_back(0);
v.push_back(0);
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
int num = std::count(v.begin(), v.end(), 0);
std::cout << num << std::endl;
//num=3
return 0;
}
自定义数据类型中必须重载==运算符
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
class Person
{
public:
std::string m_Name;
int m_Age;
bool operator==(const Person& p)
{
if (p.m_Age == m_Age)
{
return true;
}
else
{
return false;
}
}
Person(std::string name, int age)
{
m_Name = name;
m_Age = age;
}
};
int main()
{
std::vector<Person> v;
Person p1("p1", 10);
Person p2("p2", 10);
Person p3("p3", 10);
Person p4("p4", 20);
Person p5("p5", 30);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
Person p("p", 10);
int num = std::count(v.begin(), v.end(), p);
std::cout << num << std::endl;
//num=3
return 0;
}
count_if
:按照指定条件统计元素个数
count_if(iterator beg, iterator end, _Pred);
beg 开始迭代器
end 结束迭代器
_Pred 谓词
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
class Greater2
{
public:
bool operator()(int v)
{
return v > 2;
}
};
int main()
{
std::vector<int> v = { 1,2,3,4,5 };
int num = std::count_if(v.begin(), v.end(), Greater2());
std::cout << num << std::endl;
//num=3
return 0;
}
自定义数据类型:
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
class Person
{
public:
std::string m_Name;
int m_Age;
Person(std::string name, int age)
{
m_Name = name;
m_Age = age;
}
};
class Greater10
{
public:
bool operator()(const Person& p)
{
return p.m_Age>10;
}
};
int main()
{
std::vector<Person> v;
Person p1("p1", 10);
Person p2("p2", 10);
Person p3("p3", 10);
Person p4("p4", 20);
Person p5("p5", 30);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
int num = std::count_if(v.begin(), v.end(), Greater10());
std::cout << num << std::endl;
//num=2
return 0;
}
sort
:排序算法
sort(iterator beg, iterator end, _Pred);
beg 开始迭代器
end 结束迭代器
_Pred 谓词
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
void Myprint(int v)
{
std::cout << v << " ";
}
int main()
{
std::vector<int> v = { 3,4,1,5,2 };
//默认为升序
std::sort(v.begin(), v.end());
std::for_each(v.begin(), v.end(), Myprint);
std::cout << std::endl;
//降序
std::sort(v.begin(), v.end(), std::greater<int>());
std::for_each(v.begin(), v.end(), Myprint);
std::cout << std::endl;
return 0;
}
random_shuffle
:随机打乱区间元素
random_shuffle(iterator beg, iterator end);
beg 开始迭代器
end 结束迭代器
加上随机数种子实现真正的随机
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
void Myprint(int v)
{
std::cout << v << " ";
}
int main()
{
//加上随机数种子
srand((unsigned int)time(NULL));
std::vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
std::random_shuffle(v.begin(), v.end());
std::for_each(v.begin(), v.end(), Myprint);
return 0;
}
merge
:两个容器元素合并,并存储到另一容器中
merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
beg1 容器1开始迭代器
end1 容器1结束迭代器
beg2 容器2开始迭代器
end2 容器2结束迭代器
dest 目标容器开始迭代器
①两个容器必须是有序的
②目标容器需要提前开辟空间
③合并之后的容器也是有序的**
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
void Myprint(int v)
{
std::cout << v << " ";
}
int main()
{
std::vector<int> v1 = { 1,2,3,4,5 };
std::vector<int> v2 = { 1,3,5,7,9 };
std::vector<int> v3;
//目标容器需要提前开辟空间
v3.resize(v1.size() + v2.size());
std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
std::for_each(v3.begin(), v3.end(), Myprint);
//1 1 2 3 3 4 5 5 7 9
return 0;
}
reverse
:反转函数
reverse(iterator beg, iterator end);
beg 开始迭代器
end 结束迭代器
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
void Myprint(int v)
{
std::cout << v << " ";
}
int main()
{
std::vector<int> v = { 1,2,3,4,5 };
std::for_each(v.begin(), v.end(), Myprint);
std::cout << std::endl;
std::reverse(v.begin(), v.end());
std::for_each(v.begin(), v.end(), Myprint);
std::cout << std::endl;
return 0;
}
copy
:拷贝算法
copy(iterator beg, iterator end, iterator dest);
beg 开始迭代器
end 结束迭代器
dest 目标起始迭代器
目标容器需要提前开辟空间
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
void Myprint(int v)
{
std::cout << v << " ";
}
int main()
{
std::vector<int> v1 = { 1,2,3,4,5 };
std::vector<int> v2;
//目标容器需要提前开辟空间
v2.resize(v1.size());
std::copy(v1.begin(), v1.end(), v2.begin());
std::for_each(v2.begin(), v2.end(), Myprint);
return 0;
}
replace
:替换函数
replace(iterator beg, iterator end, oldvalue, newvalue);
beg 开始迭代器
end 结束迭代器
oldvalue 旧元素
newvalue 新元素
将容器内指定范围的所有旧元素修改为新元素
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
void Myprint(int v)
{
std::cout << v << " ";
}
int main()
{
std::vector<int> v = { 1,2,2,2,3,4,5 };
std::for_each(v.begin(), v.end(), Myprint);
std::cout << std::endl;
std::replace(v.begin(), v.end(), 2, 200);
std::for_each(v.begin(), v.end(), Myprint);
std::cout << std::endl;
return 0;
}
replace_if
:按条件替换元素
replace_if(iterator beg, iterator end, _pred, newvalue);
beg 开始迭代器
end 结束迭代器
_pred 谓词
newvalue 替换的新元素
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
void Myprint(int v)
{
std::cout << v << " ";
}
class Replace
{
public:
bool operator()(int v)
{
return v > 2;
}
};
int main()
{
std::vector<int> v = { 1,2,3,4,5 };
std::for_each(v.begin(), v.end(), Myprint);
std::cout << std::endl;
std::replace_if(v.begin(), v.end(), Replace(), 999);
std::for_each(v.begin(), v.end(), Myprint);
std::cout << std::endl;
return 0;
}
swap
:交换算法
swap(container c1, container c2);
c1 容器1
c2 容器2
点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
void Myprint(int v)
{
std::cout << v << " ";
}
int main()
{
std::vector<int> v1 = { 1,2,3,4,5 };
std::vector<int> v2 = { 6,7,8,9,10 };
std::cout << "交换前:\n";
std::for_each(v1.begin(), v1.end(), Myprint);
std::cout << std::endl;
std::for_each(v2.begin(), v2.end(), Myprint);
std::cout << std::endl;
std::swap(v1, v2);
std::cout << "交换后:\n";
std::for_each(v1.begin(), v1.end(), Myprint);
std::cout << std::endl;
std::for_each(v2.begin(), v2.end(), Myprint);
std::cout << std::endl;
return 0;
}
set_intersection
:求两个容器的交集
set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
beg1 容器1开始迭代器
end1 容器1结束迭代器
beg2 容器2开始迭代器
end2 容器2结束迭代器
dest 目标容器开始迭代器
①两个集合必须是有序序列
②目标容器开辟空间取两个容器最小值
③返回值是交集中最后一个元素的位置
点击查看代码
#include <iostream>
#include <vector>
#include <algorithm>
void Myprint(int v)
{
std::cout << v << " ";
}
int main()
{
std::vector<int> v1, v2, v3;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i + 5);
}
std::for_each(v1.begin(), v1.end(), Myprint);
//0 1 2 3 4 5 6 7 8 9
std::cout << std::endl;
std::for_each(v2.begin(), v2.end(), Myprint);
//5 6 7 8 9 10 11 12 13 14
std::cout << std::endl;
//目标容器开辟空间取两个容器最小值
v3.resize(std::min(v1.size(), v2.size()));
auto it = std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
std::cout << "交集:";
std::for_each(v3.begin(), it, Myprint);
return 0;
}
set_union
:求两个容器的并集
set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
beg1 容器1开始迭代器
end1 容器1结束迭代器
beg2 容器2开始迭代器
end2 容器2结束迭代器
dest 目标容器开始迭代器
①两个集合必须是有序序列
②目标容器开辟空间取两个容器空间相加
③返回值是并集中最后一个元素的位置
点击查看代码
#include <iostream>
#include <vector>
#include <algorithm>
void Myprint(int v)
{
std::cout << v << " ";
}
int main()
{
std::vector<int> v1, v2, v3;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i + 5);
}
std::for_each(v1.begin(), v1.end(), Myprint);
//0 1 2 3 4 5 6 7 8 9
std::cout << std::endl;
std::for_each(v2.begin(), v2.end(), Myprint);
//5 6 7 8 9 10 11 12 13 14
std::cout << std::endl;
//目标容器开辟空间取两个容器空间相加
v3.resize(v1.size() + v2.size());
auto it = std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
std::cout << "并集:";
std::for_each(v3.begin(), it, Myprint);
return 0;
}
set_difference
:求两个容器的差集
set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
beg1 容器1开始迭代器
end1 容器1结束迭代器
beg2 容器2开始迭代器
end2 容器2结束迭代器
dest 目标容器开始迭代器
①两个集合必须是有序序列
②目标容器开辟空间取两个容器的最大值
③返回值是差集中最后一个元素的位置
④v1与v2的差集 不同于 v2与v1的差集
点击查看代码
#include <iostream>
#include <vector>
#include <algorithm>
void Myprint(int v)
{
std::cout << v << " ";
}
int main()
{
std::vector<int> v1, v2, v3;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i + 5);
}
std::for_each(v1.begin(), v1.end(), Myprint);
//0 1 2 3 4 5 6 7 8 9
std::cout << std::endl;
std::for_each(v2.begin(), v2.end(), Myprint);
//5 6 7 8 9 10 11 12 13 14
std::cout << std::endl;
//目标容器开辟空间取两个容器最大值
v3.resize(std::max(v1.size(), v2.size()));
std::cout << "v1与v2的差集:\n";
auto it = std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
std::for_each(v3.begin(), it, Myprint);
std::cout << "\n-------------------\n";
std::cout << "v2与v1的差集:\n";
it = std::set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), v3.begin());
std::for_each(v3.begin(), it, Myprint);
return 0;
}
算术生成算法
包含头文件 'numeric'
accumulate
:计算容器元素累计总和
accumulate(iterator beg, iterator end, value);
beg 开始迭代器
end 结束迭代器
value 起始值
点击查看代码
#include <iostream>
#include <numeric>
#include <vector>
void Myprint(int v)
{
std::cout << v << " ";
}
int main()
{
std::vector<int> v;
for (int i = 0; i <= 100; i++)
{
v.push_back(i);
}
int sum = std::accumulate(v.begin(), v.end(), 0);
std::cout << sum << std::endl;
//sum=5050
sum = std::accumulate(v.begin(), v.end(), 1000);
std::cout << sum << std::endl;
//sum=5050+1000=6050
return 0;
}
fill
:向容器中填充指定的元素
fill(iterator beg, iterator end, value);
beg 开始迭代器
end 结束迭代器
value 填充的值
点击查看代码
#include <iostream>
#include <numeric>
#include <vector>
#include <algorithm>
void Myprint(int v)
{
std::cout << v << " ";
}
int main()
{
std::vector<int> v;
v.resize(10);
std::for_each(v.begin(), v.end(), Myprint);
std::cout << std::endl;
std::fill(v.begin(), v.end(), 100);
std::for_each(v.begin(), v.end(), Myprint);
std::cout << std::endl;
return 0;
}
文件操作
使用 | 来配合使用
⭐读写二进制文件不能用类似于cin cout之类的流数据读取方法,需要调用成员函数write和read向文件中写入和读取数据
- 写入到文本文件中:
①包含头文件fstream
②创建ofstream
对象并命名
③方法open(文件名,打开方式)
打开文件
④ofstream
类变量使用方法与cout
一样
⑤方法close()
关闭文件
点击查看代码
#include <iostream>
#include <fstream>
int main()
{
std::fstream fout;
fout.open("test.txt",std::ios::out|std::ios::app);//以追加方式写入
//std::fstream fout("test.txt", std::ios::out);//valid
if (!fout.is_open())
{
std::cerr << "无法打开文件";
}
//方法一:
fout << "Hello word!" << std::endl;
//方法二:
/*
const char* str = "Hello word!";
fout.write(str, sizeof(str));
*/
fout.close();
return 0;
}
- 读取文本文件:
①包含头文件fstream
②创建ifstream
对象并命名
③方法open(文件名,打开方式)
打开文件
④ifstream
类变量使用方法与cin
一样
⑤方法close()
关闭文件
点击查看代码
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream fin;
fin.open("test.txt", std::ios_base::in);
//std::ifstream fin("test.txt", std::ios_base::in | std::ios_base::app);
if (!fin.is_open())
{
std::cerr << "文件读取失败";
}
////方法一:
//char str[1024] = { 0 };
//while (fin >> str)
//{
//std::cout << str << std::endl;
//}
//方法二:
//char str[1024] = { 0 };
//fin.read(str, sizeof(str));//读取的总的字符数
//std::cout << str << std::endl;
//方法三:
//std::string str;
//while (getline(fin, str))
//{
// std::cout << str << std::endl;
//}
//方法四:
//char str[1024] = { 0 };
//while (fin.getline(str, 12))//一行文本中包含的字符数
//{
// std::cout << str << std::endl;
//}
//方法五:(不推荐)
//char c;
//while ((c = fin.get()) != EOF)
//{
// std::cout << c;
//}
fin.close();
return 0;
}
- 读写自定义数据类型文件:
点击查看代码
#include <iostream>
#include <fstream>
#include <string>
class Person
{
public:
char m_Name[64];//不能用string,会报错
int m_Age;
};
int main()
{
Person p1 = { "Tom",20 };
Person p2 = { "Jerry",10 };
std::ofstream fout("Person.txt", std::ios_base::out | std::ios_base::binary);//以二进制方式写入
fout.write((const char*)&p1, sizeof(p1));//const char*是一个指针,所以p1要加上取地址符&
fout.write((const char*)&p2, sizeof(p2));
fout.close();
std::ifstream fin("Person.txt", std::ios_base::in | std::ios_base::binary);
if (!fin.is_open())
{
std::cerr << "文件打开失败" << std::endl;
}
Person P1;
Person P2;
fin.read((char*)&P1, sizeof(P1));
fin.read((char*)&P2, sizeof(P2));
std::cout << "name:" << P1.m_Name << " age:" << P1.m_Age << std::endl;
std::cout << "name:" << P2.m_Name << " age:" << P2.m_Age << std::endl;
fin.close();
return 0;
}
- 文件指针:
对输出流:seekp()
和tellp()
对输入流:seekg()
和tellg()
seekp()
:由于fstream类使用缓冲区来存储中间数据,所以指针指向的是缓冲区中的位置,所以没什么用
seekg()
是对输入文件定位
它有两个参数:第一个参数是偏移量,第二个参数是基地址。
对于第一个参数:可以是正负数值,正的表示向后偏移,负的表示向前偏移
第二个参数:可以是
ios_base::beg:表示输入流的开始位置
ios_base::cur:表示输入流的当前位置
ios_base:🔚表示输入流的结束位置
tellg()函数不需要带参数,它返回当前定位指针的位置,也代表着输入流的大小。
点击查看代码
#include <iostream>
#include <fstream>
#include <cstdlib>
int main()
{
std::ofstream fout;
fout.open("test.txt", std::ios_base::out);
//fout.seekp(0,std::ios::beg);
fout << "123456789";
fout.close();
std::ifstream fin;
fin.open("test.txt", std::ios_base::in);
fin.seekg(-3, std::ios_base::end);
char ch;
while (fin.get(ch))
{
std::cout << ch;//789
}
fin.close();
return 0;
}