mini: false, //迷你模式 autoplay: false, //自动播放 theme: '#FADFA3', //主题色 loop: 'all', //音频循环播放, 可选值: 'all'全部循环, 'one'单曲循环, 'none'不循环 order: 'random', //音频循环顺序, 可选值: 'list'列表循环, 'random'随机循环 preload: 'auto', //预加载,可选值: 'none', 'metadata', 'auto' volume: 0.7, //默认音量,请注意播放器会记忆用户设置,用户手动设置音量后默认音量即失效 mutex: true, //互斥,阻止多个播放器同时播放,当前播放器播放时暂停其他播放器 listFolded: false, //列表默认折叠 listMaxHeight: 90, //列表最大高度 lrcType: 3, //歌词传递方式

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};

模板类vectorarray

  • 模板类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 &

typedefdecltype相结合:

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;
}
posted @ 2024-04-03 16:20  pone1  阅读(71)  评论(1编辑  收藏  举报
音乐