【C++】复习--ldm

【C++】复习


include

取余运算。实现赋初值为1,2,3…,0

int*a =new int[n];

用++i和double

1.1 程序结构

随机生成电影片名

//随机生成电影片名 
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main()
{
	int n;//length
	char c;//alpha
	srand(time(0));
	n=rand()%5+1;
	while(true)
	{
		c=rand()%26+65;
		cout<<c;
		--n;
		if(n==0) break;
	}
	return 0;
} 

1.2 面向对象编程

面向过程编程:

int add(int a,int b)
{
	return a+b;    
}

int sub(int a,int b)
{
    return a-b;
}

int main(){
    
}
很相似,相同的参数a,b,打包
    
struct cal
{
    int add(int a,int b)
{
	return a+b;    
}

	int sub(int a,int b)
{
    return a-b;
}
};
    
int main(){
    cal c;
    cout<<c.add(1,2);
}
    
都在同一个参数里,没必要做参数
    
struct cal
{
  int a,b;
  int add()  
  int sub()
};
int main(){
    int a,int b;
    cin>>a;cin>>b;
    cal c;
    c.a=a;
    c.b=b;
 	cout<<c.add();       
}

面向对象编程:结构体转化名称为类。

public和private.

private:
	int a,b;

私有的,不能再外面赋值,只能用public函数去赋值。

方法一:构造函数法:定义一个对象,紧跟赋值。cal c(1,2)。

名称和类名称一样。

struct cal{
private:
    int a,int b;
public:
    cal(int aa,int bb);
    {
        a=aa;b=bb;
    }
}

主函数不要操作,主要操作在类。

方法二:

在public内,定义一个输入函数。主函数定义之。

封装性。劣势:有时候不能接触到底层。(二次开发,中间件)。

二维坐标类:

#include <iostream>
#include <cstdlib>
using namespace std;
//类没有括号
class point
{
	private:
		int x;int y;
	public:
		point(int xx,int yy)
		{
			x=xx;
			y=yy;
		}
		void input()//给用户两种方式
		{
			cout<<"input x:";cin>>x;
			cout<<"input y:";cin>>y;
		}
		void output()
		{	
			cout<<"point:("<<x<<","<<y<<")"<<endl;
		}
};
int main()
{	
	point s(13,12);
	s.output();	
}

实例:抽奖程序,随机数:

n个同学,随机抽m个同学获奖,不能重复。(1):从n名同学抽1个。(2)不重复抽m个。

class test
{
  private:
    int n,m;
  public:
    test(int nn,int mm)
    {
        n=nn;m=mm;
        srand(time(0));
        int a[n],i;
        for(i=0;i<n;++i)
        {
            a[i]=0;
        }
    }
    void prize()
    {	
        int a[n],itemp;//n是变量,定义数组,这个编译器没出错,因为知道了是30,如果是用户现场输入,不适合。不能用静态,用动态空间new,程序运行再说有多少。int*a =new int[n];
        for(i=0;i<n;++i)
        {
            a[i]=0;
        }
        for(i=0;i<m;i++)
        {	
            while(true)
            {
                temp=rand()%n;
            	if(a[temp]==0)//在构造里定义,在price里用不了
                {	
                    cout<<temp+1<<endl;
                	a[temp]=1;
                    break;
                }
            }
            
        }
     	delete [] a;//释放一个数组的动态内存空间。
    }
    
};
int main()
{
    test(30,3);
    test.prize();
}

2.1 类的使用-初始化

c++私有变量定义都在private内。

带返回值的不要再输出,不然会有两次结果。

int output()
{
    int temp=n*n;
    cout<<"square:"<<temp<<endl;
    //return temp;
}

头文件:conio.h中两个有效函数:

  • 没有回显的函数getch() getchar()没有用

  • if(kbhit()==true) break;如果有键盘触击就退出。

c++不用float,用double。

容器:

//真实的抽奖,抽中后不再参加后续抽奖
#include <vector>  
vector <int> a;
a.push_back(i+1);
t=rand()%(a.size())
a.erase(a.begin()+t)

重载:函数名一样

同一个作用域里面函数重载的条件(仅与参数有关):1.参数类型不一样,2.参数个数不一样(函数实质上是不一样的)满足一个即可。

跟返回值无关,只看参数!

int square(int n)
double square(double n)

实际的类里面都有构造函数重载。

class cal
{
private:
    int n;
public:
    cal()//将构造函数重载。
    {
        n=10;
    }
    cal(int nn)
    {
        n=nn;
    }
    //简化写法:缺省值为10,不建议这种写法。包含了cal()
    /*cal(int nn=10)
    {
        n=nn
    }*/
};
int main()
{	
	cal c1;//初始化,没有括号。
    cal c2(12);
}

例子:

//三个构造函数
cal()
{
	y=2021;m=3;d=16;
}
cal(int dd)//只修改日子的重载构造函数,y和m不变
{	
    y=2021;
    m=3;
	d=dd;
}
cal(int mm,int dd)
{	
    y=2021;
    d=dd;
    m=mm;
}
cal(c)
//高版本编译器可以在private内赋初值。

练习:

十个数,

一个数组,找最大的数。构造函数,(重载的两个,一个初值1,2,3,…),输入函数,判断函数

定义时可以附初值。

class cal
{
private:
    a[10];
public:
    cal()
    {
        int i;
        for(i=0;i<10;++i)
        {
			a[i]=i;//取余运算。实现赋初值为1,2,3...,0
        }
    }
    cal(int n)//没有用的参数n
    {
        int i;
        for(i=0;i<10;++i)
        {
			cin>>a[i];
        }
    }
    int output()
    {
        int i,max=a[0];//赋初值为任意一个数据元素!
         for(i=0;i<10;++i)
        {
			if(max<a[i])
                max=a[i];
        }
        return max;
    }
    
};
cal()
{
	n=5;
}
cal(int nn)
{
	n=nn;
}
int output()
{
	int i,temp=1;
	for(i=1;i<=n;i++)
	{
		temp=temp*i;
	}
    return temp;
}
/*
int output(int m)
{
	if(m==0||m==1)
	{
		return 1;
	}
	else
	{
		return m*output(m-1);
	}
}
cal c; cout<<c.output(10)
*/

绝对值可以自己做,也可以abs

输入2021年的月份,返回该月的天数。

cal()
{
	n=3;
}
cal(int nn)
{
	n=nn;
}
int leap(int num)
{
    if(num%400==0||(num%4==0&&num%100!=0)
       return 1;
    else
       return 0;
}
int output()
{
    if(n==2)
        return 28+leap(y);//闰年返回1,不闰年返回0
    else if(n==4||n==6||n==9||n==11)
        return 30;
    else
        return 31;
}

输出小于整数n的所有素数。

2.2 指针与引用

静态指针:

int main():
{
    int a=10;
    int* p;//指针内放的是地址,其指向的空间是整数,定义时没有指向,指到了0。
    cout<<&a<<endl;//大地址
    cout<<&p<<endl;//小地址
    cout<<a<<endl;
    cout<<p<<endl;//0
    //*p=100;//错误,没有指向
    p=&a//指针有确定的对象了
    *p=100;
    cout<<a<<endl;//100
}

int *x; x是地址,*x该地址的值。swap(int x,int y)只是交换了值,不影响。

void swap(int *x,int *y)
{
}
swap(&a,&b);

动态指针:

运行时决定地址。使用条件:1.资源有限。2.不知道使用多少空间。

C语言如何分配单个动态变量和数组动态变量:

//单个动态
int *p;
p=(int*)malloc(sizeof(int));
scanf("%d",p);
printf("%d",*p);
//数组动态
int *p;
int n=3;
p=(int*)malloc(sizeof(int)*n);
for(i=0;i<n;i++)
{
	scanf("%d",&p[i]);    
}
for(i=0;i<n;i++)
{
	printf("%d",p[i]);   
}
free(p);//释放空间,不能占着不让别人用

C++如何分配单个动态变量:

//单个动态
int* p;
p=new int;
cin>>*p;
cout<<"addr of p"<<&p<<endl;  //0x22fe38上面是栈,下面是堆,从栈开始。指针的地址。
cout<<"addr of p->"<<p<<endl;//从堆开始,往上。指针所指空间的地址。
cout<<"addr of p->"<<&(*p)<<endl;//从堆开始,往上。两者碰头内存耗尽。
delete(p)
//数组动态
int* p;
int n=3;
p=new int[n];
cin>>p[i];
cout<<p[i]<<endl;
delete[]p;
//结构体动态
struct student
{
    string name;//用字符串,每个结构体元素中字符串占的长度不一样
    int number;
    double score;
};
student* p;
int n=3,i;
p=new student[n];
for(i=0;i<n;++i)
{
    cin>>p[i].name;
}
for(i=0;i<n;++i)
{
    cout<<p[i].name;
}

引用-给实际变量指定的别名,做函数参数

int a=10;
int& b=a;//引用是给实际变量指定的别名。
b=20;//b是a的引用,对b操作就是对a操作。
cout<<a<<endl;//输出20
return 0;

引用的使用方法:
指针的简化,都不用加*

void swap(int* a,int* b)
{
    
}
swap(a,b)//没有调用swap函数,用的是库函数,直接传入int,而不是
void swap(int& a,int& y)//不是取地址,理解为指针,需要把值返回
{
    int temp;
    temp=x;
    x=y;
    y=temp;
}
swap(a,b);
//直接对引用操作了,不用指针了,简化了。

例子:输入一个小写字母,输出大写字母

char change(char& c)//引用做函数参数用的,函数里面是对地址操作,返回值到被调用的地方。
{
	return c-32;
}
int main()
{
	char c;
	cout<<:"input a char:";
	cin>>c;
	cout<<"the change char is:"<<change(c)<<endl;
	return 0;
}

析构函数-释放空间(return之前调用)

~test()
{
	delete []a;
	cout<<"~test()"<<endl;
}

链表实现评委打分

struct score
{
    int number;
    score* next;
};
class test
{
private:
    int n;
    score* head,* end,* p;
public:
    void input()
    {
        head=new score;
        end=head;
        int i;
        for(i=0;i<n;++i)
        {
            p=new score;
            cin>>p->number;
            end->next=p;//通过移动end,改变链表。
            end=p;
        }
        end->next=NULL;
    }
    ~test()
    {
        delete head;
        delete p;
        delete end;
    }
    void browse()
    {
        p=head;
        while(true)
        {
            p=p->next;
            if(p==0) break;
           	cout<<p->number<<endl;
        }
    }
};

动态内存偏底层,关注空间,容易飞掉(1.指针指向没了,2.没有规定指针指向),用容器做。

3.1 类的继承与派生–class b:public a

子类继承了父亲, 父亲派生出子类。

原则:子类可以在任何地方使用父类。

using namespace std;
class A
{
protected:
    int m;
public:
    A(int mm)
    {
        m=mm;
    }
    void input_A()
    {
        cout<<"input m:";cin>>m;
    }
    void output_A()
    {
        cout<<"m=";cout<<m<<endl;
    }
};

class B:public A//继承方式:共有继承。B是A的子类。  子类:public 父类。此时子类和父类的private要改成protected; 
{
protected:
    int n;
public:
    B(int mm,int nn):A(mm)//父类里面也有构造函数,子类也要赡养父类。
    {
        n=nn;
    }
    void input_B()
    {
        //A::input_A()
        cout<<"input n:";cin>>n;
    }
    void output_B()
    {
        //A::output_A();
        cout<<"n=";cout<<n<<endl;
    }    
};

int main()
{
    B b(100,200);//子类给自己参数赋值以外,还得给父类初始化。
    b.input_B();
    b.output_B();
}

如果子类父类函数名一样,叫做子类重载了父类的函数,调用时默认先调用子类的函数。

父类有重载的构造,子类也要一一对应。都构造赋值。

A()
{
    m=1000;
}

//没有参数
B()//:A()(不带参数的可省)
{
    n=2000;
}

实例:年月日

class Y
{
protected:
	int y;
public:
	Y()
    {
        y=2021;
    }
    Y(int yy){y=yy;}
};

Class M:public Y
{
protected:
	int m;
public:
    M(){m=3;}
    M(int yy,int mm):Y(yy){m=mm;}
};

Class D:public M
{
protected:
    int d;
public:
    D(){d=23;}
    //构造函数三项参数,三个都有。
    D(int yy,int mm,int dd):M(yy,mm)
    {
        d=dd;
    }
    void output()
    {
        cout<<y<<"-"<<m<<"-"<<d<<endl;
    }
};

int main()
{
    D d;
    //D d(2022,3,23);
    d.output();
}

例子 点的坐标

const PI=3.1415926

class point
{
protected:
  int x,y;
public:
	point(int xx,int yy)
    {
        x=xx;y=yy;
    }
    void output()
    {
        cout<<"("<<x<<","<<y<<")"<<endl;
    }
};

class circle():public point
{
protected:
    int r;
public:
    circle()
    {
        x=0;y=3;r=10;//父类的数据都继承来了,都可以用
    }
	circle(int xx,int yy,int rr):point(xx,yy)
    {
        r=rr;
    }
    void output()
    {
        point::output();
        cout<<"r="<<r<<endl;
        cout<<"area="<<area()<<ednl;
    }
    double area()
    {
        return r*r*PI;
    }
}

int main()
{
    circle c1(1,2,3),c2(1,2,4);
    if(c1.area()>c2.area())
        c1.output();
    else
        c2.output;
    return 0;
}

3.2 ⭐运算符的重载

使常规的运算符也能适用于类的对象。

判断的运算符,比如> ==运算符 返回值是bool型

<<>>运算符 返回值是os,friend istream& iostream&

using namespace std;
class A
{
private:
    int m;
public:
    void input()
    {
        
    }
    void output()
    {
        
    }
    friend void display(A a)//display成为类A的一个朋友,函数是类的友元
    {
    //void display(A a)//以类的对象作为函数参数
    a.m=12;//不允许访问
    a.input();
    a.output();
    }
};

int main()
{
    A a;
    cin>>a;
    cout<<a;
    display(a);
    return 0;
}

功能被追加到输入输出流。

friend istream& operator>>(istream& os,A& a)//类的对象的返回值是引用,将返回值带回来。
{
    a.input();
    return os;
}
friend ostream& operator<<(ostream& os,A a)
{
    a.output();
    return os;
}
//加到友元中

双目(两个数)运算符重载在类内完成。不需要友元。

A operator+(A a2)//第一个参数省略,就是他自己。第一个运算数用类里面的自己那个参数。
{
    A temp;
    temp.m=m+a2.m;
    return temp;
}

int main()
{
    A a1,a2,a3;
    a3=a1+a2;    
    cout<<a3;
    return 0;
}

>,<的重载

bool operator>(A a2)//返回的是逻辑值。
{
    return (m>a2.m);
}

++a和a++都是a永远加一个。++在左,b也加一个。++在右,b不变。

a是变量,++a和a++是表达式。

*this是一个类。this->m/output(),或直接m/output()是一个指向。

A operator++()//++i
{
    //++m;
    //return *this;
    A temp
    temp.m=m+1;//temp表达式的值。
     m=m+1;//m自己+1
    return temp;
}
A operator++(int)//i++  随便多一个参数,int 在 括号内是为了向编译器说明这是一个后缀形式,而不是表示整数。
{
    //A old=*this;
    //++(*this)
    //return old;
    A temp;//this指针
    temp.m=m;//temp表达式的值。
    m=m+1;//m自己+1
    return temp;
}
int main()
{
    A a,b;
    b=++a;
    b=a++;
    cout<<a;
	cout<<b;
}

局部的类的对象,如果其中包含动态数组,因为返回后会调用,会调用析构,会把自己的指针释放掉,内存释放掉,会飞掉。

4.1 容器

1.固定数组的缺陷,过于固定,插入删除无法实现,而且作为函数参数带个尾巴。

2.动态数组可以,但有时候不行。

#动态数组构造方法
private:
	int* a;
public:
	a=new int[n];
int add(int a[],int n)
{
    int sum=0,i;
    for(i=0;i<n;++i)
    {
        sum=sum+a[i];
    }
    return sum;
}

数组,越界会提醒,n必须是常量。

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
const int n=100;
int main()
{
    vector<int>a;
    int i;
    srand(time(0));
    for(i=0;i<n;++i)
    {
        a.push_back(rand());//压随机数
    }
    for(i=0;i<n;++i)
    {
        cout<<a[i]<<endl;
    }
    return 0;
}

a.push_back()压入元素。

a.begin()。容器开头指针。

a.size()。知道容器大小。

a.erase() 擦除元素。

容器作为函数参数

int add(vector a)
{
    int i=0,sum=0;
    for(i=0;i<a.size();++i)
    {
        sum+=a[i];
    }
}

cout<<"sum="<<add(a)<<endl;

class()

抽奖的容器例子:

class test
{
private:
    int n,m,i;
 	vector<int>a;
public:
    test(int nn,int mm)
    {
        n=nn;m=mm;
        for(i=0;i<n;++i)
        {
            a.push_back(i+1);
        }
        srand(time(0));
    }
    void prize()
    {
        for(i=0;i<m;++i)
        {
            temp=rand()%a.size();
            cout<<a[temp];
            a.erase(a.begin()+temp);
        }
    }
};
int main()
{
    test t(30,10);
    t.prize();
    t.
}

提分程序容器 ++重载提分

class stu
{
private:
    int n;
    vector<int>a;
public:
    stu(int nn)
    {
        n=nn;
        int temp;
        while(true)
        {
            cin>>temp;
            if(temp>0)
	            a.push_back(temp);
            else
                break;
        }
    }
    void output()
    {
      
    }
    stu operator++(//对++重载,返回的是类
    {
    	int i;
        for(i=0;i<a.size();++i)
        {
            if(a.[i]<60)
            {
                a[i]=60;
            }
            else if(a[i]==60)
                a[i]=61;    

        }
    }    
};

缺点

vector 是顺序存储的,没有指针,从中间删除或插入多个元素时,整体搬家,开销比较大。

⭐数组排序,容器排序

sort函数包含在:#include

#include <cstdlib>
#include <vector>
#include <algorithm>//含有一个传统的排序函数
const int n=10000000;
class test
{
private:
    int i,j,k;
    int a1[n];
    vector<int>a2;
public:
    test()
    {
        srand(time(0));
        for(i=0;i<n;++i)
        {
            a1[i]=rand();
        }
        for(i=0;i<n;++i)
        {
            a2.push_back(rand());
        }
    }
    void browse1()
    {
        for(i=0;i<n;++i)
        {
            cout<<a1[i];
        }
    }
    void Sort_1()//选择排序 记住最大下标,最后才交换。
    {
        for(i=0;i<n;++i)
        {
            k=i;
            for(j=i+1;j<n;++j)
            {
                if(a1[k]<a1[j])
                    k=j;
            }
            temp=a1[i];
            a1[i]=a1[k];
            a1[k]=temp;
        }
    }
    static bool cmp(int n1,int n2)//静态函数,编译时,跟着类走,不跟对象走
    {
        return n1>n2;//从小到大排序
    }
    void Sort_2()
    {
        sort(a1,a1+n,cmp);//排序规则函数,不加规则函数默认从小到大排序
    }
    void Sort_3()
    {
        sort(a2.begin(),a2.end(),cmp)
    }
};

int main()
{
    test t;
    clock_t tt;//计时器
    tt=clock();
    t.Sort_1();
    t.browse1();//观察时注释掉这个数据,只看排序所用时间
    cout<<"time of simple sort:"<<clock()-tt<<endl;
    cout<<"=============="<<endl;
    tt=clock();
    t.Sort_2();
    t.browse1();//观察时注释掉这个数据,只看排序所用时间
    cout<<"time of simple sort:"<<clock()-tt<<endl;
    cout<<"=============="<<endl;
    return 0;
}

实际数据库里多项数据。一个数据库也可以用容器去做。

struct S
{
    int number;
    int score;
};
vector<S>a;//容器a里面都是结构体元素。
S t;
t.number=rand();t.score=rand();
a.push_back(t);
static bool cmp(S s1,S s2)//规则函数修改,参数与对象类型一样
{
    return s1.score>s2.score;//成绩由大到小。
}

迭代器

迭代器是指向容器内元素的指针。

是数组型容器。可以用下标访问。

还有其他很多

vector::iterator p,p_max;

输入时,还是从1-n。

遍历时采用迭代器。

for(p=a.begin(),p!=a.end(),++p)
{
    cout<<p->number<<"-"<<p->score<<endl;
}
void max()
{
    p_max=a.begin();
    for(p=a.begin();p!=a.end();++p)
    {
        if(p_max->score>p->score) p_max=p;
    }
    cout<<p_max->number<<"-"<<p_max->score<<endl;
}

4.2 list容器(双向链表),map容器

结构体检索总结

find函数

在结构体内建立起检索规则函数,这个参数作为find函数第三个参数,也即find函数第三个参数必须是值。

bool operator==(S s/int t)//这里的参数和find函数的第三项相对应。但本质都是对一个数据或者字符串进行检索,如果是S s,则需要在Find大函数内初始化一个s结构体,并赋值,检索,如果只是int t,则可以作为Find(int t)的参数,在find内检索。
{

}
void Find()
{
    
}
find_if函数

find_if函数第三个对象是一个匹配规则。可以是一个具体的函数对象。

static bool find1(S s)
{
	return s.money<5000;
}
find_if(p,a.end(),find1)

vector

1、简单元素:整数
(1)遍历的方法
(2)find函数:p=find(a.begin(),a.end(),234);
2、复合元素:结构体
(1)排序规则函数:类内( static)
(2)检索规则函数:结构体内(重载= =)
(3)检索任意字段的方法:结构体增加index项

struct S
{
  int number;
  int score;
  int index;
  bool operator==(S s)//规定查找的规则函数,双等号重载只能有一个,如果有时候想查学号,又想查姓名 再添加一个
  {
      if(s.index==1)
      	return score==s.score;
      if(s.index==2)//score<s.score  返回小于的
  }
};
class test()
{
private:
    vector<S>a;
    vector<S>::iterator p;
    int n,i;
    S t;
   
public:
    test(int nn)
    {
        n=nn;
        srand(time(0));//把随机数种子放在这
        for(i=0;i<n;++i)
        {
        	t.number=rand();
            t.score=rand();
            a.push_back(t);//从尾部开始压入
        }
    }
    void browse()
    {
        for(p=a.begin();p!=a.end();++p)//a.end()是个标识,内部没有元素,是空
        {
            cout<<p->number<<"-"<<p->score<<endl;
        }
    }
    void Sort()//S是大写,不然与sort重名
    {
        sort(a.begin(),a.end());//默认由小到大,复合元素,必须给定要排的东西
    }
    static bool cmp1(S s1,S s2)//cmp1,cmp2编两个函数,排序
    {
        return s1.score>s2.score;//成绩由大到小排序
    }
    //数据库的操作最重要的是检索。
    void Find(int m)
    {
        p=a.begin();
        t.score=m;
        while(true)
        {
            p=find(p,a.end(),t);//find函数前两个参数都是迭代器,第三个参数一定是结构体型的
        	if(p!=a.end())
            {
                cout<<p->number<<'-'<<p->score<<endl;
                ++p;
            }
            else break;
        }
    }

};
int main()
{
    test t(10);
    t.Sort();
    t.browse();
    t.Find(91);
    return 0;
}

list

list双向链表不考虑排序,想排就导入容器

1、简单元素:整数
(1)插入与删除:比vector开销少!
(2)find函数:同vector
2、复合元素:结构体
(1)排序困难:不能用sort
(2)检索数据:同vector

void Insert()
void insert
{
	p=a.end();
	--p;
	a.insert(p,12345);
}

#Include

class test
{
private:
    list<int>a;
    list<int>::iterator p;
    int n,i;
public:
    test(int nn)
    {
        n=nn;
        srand(time(0));
        for(i=0;i<n;++i)
        {
            a.push_back(rand());
        }
    }
    void browse()
	{
        for(p=a.begin();p!=a.end();++p)
        {
            cout<<*p<<endl;
        }
	}
    void Del()
    {
        p=a.end();
        --p;--p;
        a.erase(p);
    
    void Insert()
    {
        p=a.end();
        --p;
        a.insert(p,12345);
    }
    
    void Find(int m)
    {
        p=a.begin();
        while(true)
        {
            p=find(p,a.begin(),m);
            if(p!=a.end())
            {
                cout<<*p<<end;
                ++p;
            }
            else break;
        }
    }
};
    
int main()
{
    test t(10);
    t.browse();
    
    t.Del();
    t.browse();
    
    t.Insert();
    t.browse();
}

实验时构造函数内压入,而不是使用迭代器。

map

1、map用法
map<key,data> a;
map<key,data>::iterator p;
2、map检索:精确匹配

需要a.find,而vector只需要find/find_if p=a.find(“003”);
3、map元素类型
(1)<key,简单类型>
(2)<key,结构体>
4、map实例:英汉词典

#include

不管正序,倒序,最后都会按二叉树,按键值,从小到大排序。

list容器不能用容器的:p=a.end()-2;因为list本质是链表,p是指针,只能--地去挪动。

另外list的a.end()指向最后一个数据,而不是vector的最后一个数据的下一个位置。

要求:压入的是键值,不会压入键值重复的记录。

class test
{
private:
	map<int,int>a;//第一个是键,第二个是整数
    map<int,int>::iterator p;
    int n,i;
public:
    test(int nn)
    {
        n=nn;
        sramd(time(0))
        for(i=0;i<n;++i)
        {
            a.insert(pair<int,int>(i+1,rand()));//第一个函数
        }
    }
    void browse()
    {
        for(p=a.begin();p!=a.end();++p)
        {
            cout<<p->first<<"-"<<p->second<<endl;
        }
    }
    void Find(int m)//找的是键
    {
        p=a.find(m);//是map自己内部的函数
    	if(p!=a.end())
        {
            cout<<p->first<<"-"<<p->second<<endl;
        }
        else cout<<"no record"<<endl;
    }
};
int main()
{
    test t(10);
    t.browse();
    return 0;
}

struct S
{
    int number;
    int score;
};
class test
{
private:
	map<int,S>a;//第一个是键,第二个是整数
    map<int,S>::iterator p;
    int n,i;
    S t;//定义临时变量t;
public:
    test(int nn)
    {
        n=nn;
        sramd(time(0))
        for(i=0;i<n;++i)
        {
            a.insert(pair<int,S>(i+1,t));//第一个函数
        }
    }
    void browse()
    {
        for(p=a.begin();p!=a.end();++p)
        {
            cout<<p->first<<"-"<<p->second.number<<"-"<<p->second.score<<endl;
        }
    }
    void Find(int m)//找的是键
    {
        p=a.find(m);//是map自己内部的函数
    	if(p!=a.end())
        {
            cout<<p->first<<"-"<<p->second.number<<"-"<<p->second.score<<endl;
        }
        else cout<<"no record!"<<endl;
    }
};
int main()
{
    test t(10);
    t.browse();
    return 0;
}

要查只能遍历去查。(内部是在移动指针

find/find_if/for_each

find:

struct S
{
	int number;
	int score;	
	bool operator==(S s)
	{
		return score<s.score;
	}
};

void Find(int m)
{
    t.score=m;
    p=a.begin();
    while(true)
    {
        p=find(p,a.end(),t);
        if(p!=a.end())
        {
            cout<<p->number<<"-"<<p->score<<endl;
            ++p;
        }
        else break;
    }
}

5.1

容器复习

涉及到容器的规则函数都用静态的。

类内创建的与容器配套的规则与处理函数,都要加static.即函数名作为参数的那些函数。

struct S
{
};
vector<S>a;
S t;
static void display(S s)
    
static void add(S& s)
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <conio.h>

using namespace std;

struct S
{
  int number;
  int score;
  bool operator==(S s)//s是第二个元素
  {
  	return score==s.score;//score是第一个元素的
  }
};
class test
{
private:
    vector<S>a;
    vector<S>::iterator p;
    S t;
    int i,n;//两个变量
public:
    test(int nn)
    {
        n=nn;
        srand(time(0));
        for(i=0;i<n;++i)
        {
            t.number=rand();t.score=rand();
            a.push_back(t);
        }
    }
    void browse()
    {
        for(p=a.begin();p!=a.end();++p)
        {
            cout<<p->number<<"-"<<p->score<<endl;
        }
    }
    static bool cmp(S s1,S s2)//静态的和类的代码一起,减小代码量
    {
    	return s1.score>s2.score;
	}
	static bool find1(S s)
	{
		return s.number==s.score;
	}
    void Sort()
    {
    	sort(a.begin(),a.end(),cmp);
	}
	
	void Find(int m)//查m
	{
		t.score=m;//查的是t.score这个m
		p=a.begin();
		while(true)
		{
			//p=find(p,a.end(),t);//查元素类型是t这个结构体
			p=find_if(p,a.end(),find1);//条件查询,第三项是个特殊的函数,参数里面带参数需要额外的操作,这里不那么办
			if(p!=a.end())
			{
				cout<<p->number<<"-"<<p->score<<endl;
				++p;
			}
			else break;
		}
	}
	static void display(S s)
	{
		cout<<s.number<<"-"<<s.score<<endl;		
	}
	static void add(S& s)//加引用,把值带回来
	{
		s.score=s.score+100;
	}

	void output()
	{
		for_each(a.begin(),a.end(),display);
		cout<<"========"<<endl;
		for_each(a.begin(),a.end(),add);
		for_each(a.begin(),a.end(),display);
	}
};
int main()
{
	test t(10);
//	t.Find(123);
	t.output();
//	t.Sort();
//	t.browse();
}

文本方式,屏幕大小,水平80行,垂直25列。

计时器与多线程

最少10ms.

擦除->坐标变换->重新画

a.end()实际上指向的是最后一个元素的下一个位置。

//自主运动的小球 
#include <windows.h>
#include <iostream>
#include <ctime>
#include <list>
#include <iomanip>
#include "basic.cpp"
using namespace std;
struct S
{
	int x,y;
};
class test
{
private:
	clock_t t1,t2,t3;
	int x,y;	
	list<S>a;
	list<S>::iterator p,p1;
public:
	test()
	{
		x=10;y=10;
		t1=clock();t2=clock();t3=clock();
	}
	void draw(int x,int y)
	{
		gotoxy(x,y);
		cout<<"●";
	}	
	void erase(int x,int y)
	{
		gotoxy(x,y);
		cout<<"  ";
	}
	void move1()//炮台
	{
		if(clock()-t1>50)
		{
			draw(x,y);
			t1=clock();
		}
	}
	void move2()//key
	{
		if(clock()-t2>50)
		{
			erase(x,y);
			if(GetAsyncKeyState(VK_ESCAPE))exit(0);
			if(GetAsyncKeyState(VK_UP))--y;
			if(GetAsyncKeyState(VK_DOWN))++y;
			if(GetAsyncKeyState(VK_LEFT))--x;
			if(GetAsyncKeyState(VK_RIGHT))++x;
			if(GetAsyncKeyState(VK_SPACE))
			{
				S t;
				t.x=x;t.y=y-1;
				a.push_back(t);
			}
			draw(x,y);
			t2=clock();
		}
	}	
	void move3()//炮弹
	{
		if(clock()-t3>50)
		{
			for(p=a.begin();p!=a.end();)
			{
				erase(p->x,p->y);
				--(p->y);
				if (p->y<0)
				{
					p=a.erase(p);//p指向下一个节点 
				}
				else
				{
					draw(p->x,p->y);
					++p;
				}
			}
			t3=clock();
		}
	} 
	void move()//control
	{
		while(true)
		{
			move1();
			move2();
			move3();
		}
	}
};
int main()
{
	test t;
	t.move();
	return 0;	
}

5.2 String 字符串

复习小球

#include<windows.h>
#include<iostream>
#include<string>
#include<cstdlib>
#include<ctime>
#include"basic.cpp"
using namespace std;

class test
{
private:
	clock_t t1,t2;
	int x,y;
public:
	test()
	{
		x=10;y=10;
		t1=clock();
		t2=clock();//几个线程就初始化几个计时器
	}
	void draw()
	{
		gotoxy(x,y);
		cout<<"H";
	}
	void erase()
	{
		gotoxy(x,y);
		cout<<" ";
	}
	void move1()
	{
		if(clock()-t1>50)
		{
			draw();
			t1=clock();
		}
	}
	void move2()//keyboard进程,炮弹也在这里
	{
		if(clock()-t2>50)
		{
	//由于有坐标变化,需要先擦除后,画
			erase();
			if(GetAsyncKeyState(VK_ESCAPE)) exit(0);
			if(GetAsyncKeyState(VK_UP)) --y;
			if(GetAsyncKeyState(VK_DOWN)) ++y;
			if(GetAsyncKeyState(VK_LEFT)) --x;
			if(GetAsyncKeyState(VK_RIGHT)) ++x;
			draw();
			t2=clock();
		}
	}
	void Move()
	{
		while(true)
		{
			move1();
			move2();
		}
	}
};
int main()
{
	test t;
	t.Move();
	return 0;
}

字符串

string s="1215151";
string::size_type n;//定义长度变量n
n=s.max_size();
cout<<s.size()<<endl;
cout<<s.max_size()<<endl;

string s="1234567890";
	string::size_type n;
//	s=s.erase(3,2);//字符串是从0位置开始,擦除第三个位置,即4和5。
//	s=s.insert(3,"abc");//在前面插入
//	s=s.replace(3,2,"abc");//从第三个位置开始替换,替换两个,字符是abc
	string s1="45";
	if(s.find(s1,0)!=string::npos)//从0开始找
	{
		n=s.find(s1,0);//返回找到的位置。
		cout<<n<<endl;
		s=s.substr(n,2);//取从n开始的长度为2的字符串
		cout<<s<<endl;
	}
using namespace std;

int main()
{
	string s="-12-34-56-78-90-";
	string::size_type n1,n2,pos=0;
	string s1;
	while(true)
	{
		n1=s.find("-",pos);
		n2=s.find("-",n1+1);
		s1=s.substr(n1+1,n2-n1-1);
		cout<<s1<<endl;
		pos=n2;
		if(pos+1>=s.size()) break;//假设字符串长度是4,则最远到3,pos+1才行。
	}

	return 0;
}
⭐字符串问题 要先赋值,获得空间
string reverse(string s)
{
	❌string temp;//得先获得内容,不然赋值不知道辅到哪里了。
	string temp=s;
	//or
	n=s.size();
	string temp;
	temp.resize(n);
	
}
⭐字符串 转换为任何想要的元素 主要是数字
#include <string>
#include <sstream>
int str2int(string s)
{
	stringstream ss;
	int n;
	ss<<s;
	ss>>n;
	return n;
}
⭐字符串处理,复合元素

三个-确定一个数据, pos=n3修改起始位置,while循环遍历。

int main()
{
	string s="-王小二-12-李小二-34-张小三-56-";
	string::size_type n1,n2,n3,pos=0;
	string s1;
	while(true)
	{
		n1=s.find("-",pos);
		n2=s.find("-",n1+1);
         n3=s.find("-",n2+1);
		s1=s.substr(n1+1,n2-n1-1);
        s2=s.substr(n2+1,n3-n2-1);
		cout<<s1<<endl;
        cout<<s2<<endl;
		pos=n3;
		if(pos+1>=s.size()) break;//假设字符串长度是4,则最远到3,pos+1才行。
	}

	return 0;
}
⭐相同分隔符的元素,取出到容器中

使用两个string::size_type 一前一后去取数据。

test(){s="-123-1234-12345-";}	
	void input()
	{
		string::size_type pos,n;
		pos=0;
		while(true)
		{
			if(s.find("-",pos)!=string::npos)
			{
				pos=s.find("-",pos);
				n=++pos;
				if(s.find("-",pos)!=string::npos)
				{
					pos=s.find("-",pos);
					a.push_back(s.substr(n,pos-n));
				}
				else break;
			}
			else break;
		}
	}

模糊检索 (有效率)

int main()
{
	string s="-王小二-12-李小二-34-张小三-56-";
    stirng ss="小二";
	string::size_type n1,n2,n3,pos=0;
	string s1;
	while(true)
	{
        if(s.find(ss,pos)!=string::npos)
        {
        n1=s.find(ss,pos);
        n1=s.rfind("-",n1);//逆向去找,取出全称
		n1=s.find("-",pos);
		n2=s.find("-",n1+1);
         n3=s.find("-",n2+1);
		s1=s.substr(n1+1,n2-n1-1);
        s2=s.substr(n2+1,n3-n2-1);
		cout<<s1<<endl;
        cout<<s2<<endl;
		pos=n3;
//		if(pos+1>=s.size()) break;//假设字符串长度是4,则最远到3,pos+1才行。    
        }
        else break;
	}

	return 0;
}

单词查找

正向
	string s="moon   n.月亮",s1,s2;
	string::size_type n1,n2;
	n1=s.find(" ",0);
	n2=n1;
	while(true)
	{
		if(s[n2]==" ")
			++n2;
		else break;
	}
	s1=s.substr(0,n1);
	s2=s.substr(n2,s.size()-n2);
	cout<<s1<<endl;
	cout<<s2<<endl;
双向/解析英文词条
	string s="moon   n.月亮",s1,s2;
	string::size_type n1,n2;
	n1=s.find(" ",0);
	n2=s.rfind(" ",s.size());
	s1=s.substr(0,n1);
	s2=s.substr(n2+1,s.size()-n2-1);
	cout<<s1<<endl;
	cout<<s2<<endl;
int main()
{
	string s="ability   n.能力",s1,s2;
	string::size_type n1,n2;
	n1=0;
	n2=s.find(" ",n1);
	s1=s.substr(n1,n2-n1);
	cout<<s1<<endl;
	//=====================
	n1=n2+1;
	while(true)
	{
		if(s[n1]==' ')
			++n1;
		else 
			break;
	}
	n2=s.size();
	s2=s.substr(n1,n2-n1);
	cout<<s2<<endl;
	return 0;
}
倒序
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <ctime>

using namespace std;
string reverse(string s)
{
	string::size_type i,n;
	n=s.size();
	string temp=s;
	for(i=0;i<n;++i)
	{
		temp[i]=s[n-i-1];
	}
	return temp;
}
string change1(string& s)
{
	string::size_type i,n;
	n=s.size();
	for(i=0;i<n;++i)
	{
		s[i]=s[i]+5;
	}
	return s;
}
string change2(string& s)
{
	string::size_type i,n;
	n=s.size();
	for(i=0;i<n;++i)
	{
		s[i]=s[i]-5;
	}
	return s;
}
int main()
{
	string s="今晚12点,图书馆门口见!";
	s=reverse(s);
	cout<<s<<endl;
	s=reverse(s);
	cout<<"=======";
	cout<<s<<endl;
	return 0;
}

字符串的编码解码在ASCII的中间部分。空间很大。

测试数字字符串

转换函数非常必要

数据库里面的数据都是字符串

判断数字函数 isdigit()

if(!isdigit(s[i]))

统计字串

字串统计找到一个后,要++其位置,不然总是原地踏步地去找。另外要判断

string::size_type n1;
n1!=string::npos

6.1 文件类型

实验一:综合字符串流转换类型和取字符判断数字

#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

class test
{
private:
	string s,ss;
	string::size_type n1,n2,pos=0;
	ofstream f;
public:
	test()
	{
		ss="";
		cout<<"input a string:";cin>>s;
		f.open("001.txt",ios::out);
		if(!f)
			cout<<"file open error!"<<endl;
	}
	int str2num(string a)
	{
		stringstream s;
		s<<a;
		int n;
		s>>n;
		return n;
	}
	void get()
	{
		int i=0;
		for(i=0;i<s.size();++i)
		{
			if(s[i]>='0'&&s[i]<='9')
				ss+=s[i];
		}
		cout<<ss<<endl;
		int n=str2num(ss);
		f<<n;
		f.close();
	}
};
int main()
{
	test t;
	t.get();
	return 0;
}

⭐注意:输入输出流和getline

getline(f,t)//把f取字符串到t

输入输出流则是可以拿到特定的数据。

一条竖线是按位或,逻辑或是两条竖线。

00000001
00000010
-------------
00000011

#include //文件流

二进制文件,文本文件。

操作方式不一样

文本文件对于 100000 是6个字符,文本文件是二字节。二进制文件是int型,4字节。

文件操作方式 out是往文件内写 in 是往文件外读

	string s="Hello world";
	//ofstream f1("f1.txt",ios::out);//操作方式是out,文件句柄ofstream
	ofstream f1("f1.txt",ios::app);//操作方式是append
	if(f1)
	{
		f1<<s<<endl;//这里也输入了换行符。
		f1.close();
	}
	else
		cout<<"file open error!"<<endl;
	return 0;

读取

if(f2)
	{
		f2>>s1;//只能读一行,而且每次读的一行只读到空格,这是>>读取的缺陷。
		getline(f2,s1);
		cout<<s1<<endl;
		getline(f2,s1);
		cout<<s1<<endl;//getline()可以读取空格及其后的内容,读取的是字符串,而f>>可以是int
		f2>>s1;
		cout<<s1<<endl;
	}

循环读取,全部内容

if(f2)
	{
		while(!f2.eof())
		{
			getline(f2,s1);
			cout<<s1<<endl;
		}
	}

⭐读文件函数 一定要将文件名通过.c_str()转换

void read_file(string filename)
{
	string s1;
	ifstream f2(filename.c_str(),ios::in);//转换为c语言字符
	if(f2)
	{
		while(!f2.eof())
		{
			getline(f2,s1);
			cout<<s1<<endl;
		}
	}
	else cout<<"file open error!"<<endl;

}

找单词

没有重复的,而且能快速查找。map容器,高效率查找。

class test
{
private:
	ifstream f;
	string s,word,s1;
	string::size_type n;
public:
	test()
	{
		f.open("dictionary.txt",ios::in);
		if(!f)
		{
			cout<<"file open error!"<<endl;
		}
	}
	void dict()
	{
		cout<<"input a word:";cin>>word;
		//moonlight n.月光
		while(!f.eof())
		{
			getline(f,s);
			n=s.find(" ",0);//找什么,从哪开始找
			s1=s.substr(0,n);//从哪取,取多长
			if(s1==word)
			{
				cout<<s1<<endl;//硬盘操作,浪费硬盘。读取到内存,对内存操作,不会损坏硬盘。
				break;
			}
		}
	}
};

map函数快速找

#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <map>
#include <algorithm>
using namespace std;


class test
{
private:
	ifstream f;
	string s,word,s1;
	string::size_type n;
	map<string,string>a;
	map<string,string>::iterator p;
public:
	test()
	{
		f.open("dictionary.txt",ios::in);
		if(!f)
		{
			cout<<"file open error!"<<endl;
		}
		else
		{
			while(!f.eof())
			{
				getline(f,s);
				n=s.find(" ",0);//找什么,从哪开始找
				s1=s.substr(0,n);//从哪取,取多长
				a.insert(pair<string,string>(s1,s));
			}
			f.close();
		}
	}
	void dict()
	{
		cout<<"input a word:";cin>>word;
		//moonlight n.月光
		p=a.find(word);
		if(p!=a.end())
		{
			cout<<p->second<<endl;
		}
		else
		cout<<"No such word in the dict!"<<endl;
	}
};
int main()
{
	test t;
	t.dict();
}

字符串存储查找 模糊查询

	void dict()
	{
		cout<<"input a word:";cin>>word;
		//#moonlight n.月光#
		pos=0;
		while(true)
		{
			if(s.find(word,pos)!=string::npos)
			{
				n1=s.find(word,pos);
				n1=s.rfind("#",n1);
				n2=s.find(" ",n1);
				n3=s.find("#",n2);
				s1=s.substr(n1+1,n2-n1-1);
				s2=s.substr(n1+1,n3-n1-1);
				//if(s1==word){
					cout<<s2<<endl;
					//break;	
				//}
				         
				pos=n3;
		}
			else break;
		}
	}

一条竖线是按位或,逻辑或是两条竖线。

⭐容器求和函数accumulate()

vector<double>a;
double b=accumulate(a.begin(),a.end(),0;

注意:
accumulate 函数第三个参数初值 赋值的时候一定要注意 所累加的vector的类型,如果vector是float或者double型, 赋值的时候如果给0,而不是0.0,那么就会出现累加的小于1的数都是0;因此如果是float或double类型的vector,使用accumulate时第三个参数应为0.0,否则就会出错。

6.2 二进制方法操作文件

s->s.c_str() 由字符串转为字符(常数)指针。

以程序为主体,程序往磁盘内写是out。磁盘往文件内是in。

文件只有一种,操作方式有两种,一种是文本文件去操作,一种是二进制文件去操作。

二进制操作可以同时读写。

f.seekg()//读文件指针,seek get()。

f.seekp()//写文件指针,seek put()。

紧跟f.write((char*)s.c_str(),n);s

image-20210417102816190

image-20210417102803766

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

class test
{
private:
	fstream f;
	string s;
	string::size_type n;
public:
	test()
	{
		f.open("f1.txt",ios::in|ios::out|ios::binary);
		if(!f)
		{
			cout<<"file error!"<<endl;
		}
		s="123";
	}
	void turn()
	{
//		int m=123456;
		f.seekp(0,ios::beg);//设置输出文件流的文件流指针位置,偏移量是0,
		f.write((char*)s.c_str(),s.size());//写什么,地址,转换为c字符串,写多少个字节。
//		f.write((char*)&m,sizeof(m));//整数变量还是4个字节,会写入4个大小,如果存的是abcde,则e会保留,前四位不可见,是乱码。
	}
	~test()
	{
		f.close();
	}
};
int main()
{
	test t;
	t.turn();
}

文件倒序

void turn()
	{
//		int m=123456;
		f.seekg(0,ios::end);//设置输入文件流的文件流指针位置,读指针移到文件尾
		n=f.tellg();//读取长度
		s.resize(n);//字符串开辟空间
		f.seekg(0,ios::beg);//移动指针到文件头
		f.read((char*)s.c_str(),n);//读字符串
		f.seekp(0,ios::beg);
		f.write((char*)s.c_str(),n)
	}
string reverse(string n)
{
    string temp=s;
    n=s.size();
    for(i=0;i<n;++i)
    {
        temp[i]=s[n-i-1];
    }
    return temp;
}

文件打开状态,不让操作。

image-20210417104453573

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

class test
{
private:
	fstream f;
	string s;
	string::size_type n;
public:
	test()
	{
		f.open("test.doc",ios::in|ios::out|ios::binary);
		if(!f)
		{
			cout<<"file error!"<<endl;
		}
	}
	void turn()
	{
//		int m=123456;
		f.seekg(0,ios::end);//读指针移到文件尾
		n=f.tellg();//读取长度
		s.resize(n);//字符串开辟空间
		f.seekg(0,ios::beg);//移动指针到文件头
		f.read((char*)s.c_str(),n);//读字符串
		s=reverse(s);
		f.seekp(0,ios::beg);
		f.write((char*)s.c_str(),n);
	}
	string reverse(string s)
	{
		int i;
		string temp=s;
		n=s.size();
		for(i=0;i<n;++i)
		{
			temp[i]=s[n-i-1];
		}
		return temp;
	}
	~test()
	{
		f.close();
	}
};
int main()
{
	test t;
	t.turn();
}

文件切割加密

	void turn()
	{
		f.seekg(0,ios::end);//读指针移到文件尾
		n=f.tellg();//读取长度
		s.resize(n);//字符串开辟空间
		f.seekg(0,ios::beg);//移动指针到文件头
		f.read((char*)s.c_str(),n);//读字符串
		//文件切割
//		s1=s.substr(0,100);//0-99
//		s2=s.substr(100,n-100);
		s1=s.substr(0,n-100);
		s2=s.substr(n-100,100);
		s=s2+s1;
//--------------------------
		
//		s=reverse(s);
		f.seekp(0,ios::beg);
		f.write((char*)s.c_str(),n);
	}

文件

把字符串样例写出来,边写代码,边敲。

大竞赛—二进制文件

对文件生成的exe文件进行操作,把提示信息改成中文。

当指针进入到f.eof()时,将不能再移动。必须使用"f.clear()"才能清楚锁定,然后才可以移动。

7.1 C++其他内容

复习二进制文件

析构函数写回去。

想破坏一个文件,把第一个ascii码加5就破坏掉了。

全部读入

void turn1()
	{
		f.seekg(0,ios::end);
		n=f.tellg();
		s.resize(n);
		f.seekg(0,ios::beg);
		f.read((char*)s.c_str(),n);
		//============================================
		s[0]=s[0]+5;
		//============================================
		f.seekp(0,ios::beg);
		f.write((char*)s.c_str(),n);
	}

改一个字节

void turn2()
{
    f.seekg(0,ios::end);
    f.read(&c,1);
    //============================================
    c=c+5;
    //============================================
    f.seekp(0,ios::beg);
    f.write((&c,1);
}

输出exe的第一个字符

	void turn2()
	{
		f.seekg(0,ios::end);
		f.read(&c,1);
		//============================================
		//c=c+5;
		cout<<c<<endl;
		//============================================
		//f.seekp(0,ios::beg);
		//f.write((&c,1);
	}

c++模板 ⭐小题5分

using namespace std;
int add(int a,int b)
{
	return a+b;
}
double add(double a,double b)
{
	return a+b;
}
int main()
{
	cout<<add(1,2)<<endl;
	cout<<add(1.5,2.3)<<endl;
	return 0;
}

两个重载函数,类型不一样,把类型设为模板。

模板就是类型作为参数。

template<class T>类型参数用class定义,T是我们起的名字,那么这个函数就是模板函数。

容器vectora也是个模板。

函数使用时要指定其模板。

做底层,做库,做中间件,让别人二次开发用,让函数支持多个参数,就是用模板。

using namespace std;
template<class T>
T add(T a,T b)
{
	return a+b;
}
int main()
{
	cout<<add<int>(1,2)<<endl;
	cout<<add<double>(1.5,2.3)<<endl;
	return 0;
}
练习:字符串转换为其他类型的模板
#include <iostream>
#include <conio.h>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;
template<class T>
T str2T(string s)
{
	T temp;
	stringstream ss;
	ss<<s;//扔进去
	ss>>temp;//捞出来
	return temp;
}
int main()
{
	cout<<str2T<int>("12")+100<<endl;
	cout<<str2T<double>("12.5")+100<<endl;
	return 0;
}
类模板:类里面用T
typeid函数需要头文件,typeinfo

test t1(1,2);

template<class T>

class test
{
private:
	T a,b;
public:
	test(T aa,T bb)
	{
		a=aa;b=bb;
	}
	void output()
	{
		if(typeid(T)==typeid(int))
			cout<<a+b<<endl;
		else if(typeid(T)==typeid(string))
		{
			cout<<str2int(a)+str2int(b)<<endl;
		}
	}
	int str2int(T s)
	{
		int temp;
		stringstream ss;
		ss<<s;
		ss>>temp;
		return temp;
	}
};

int main()
{
	test<int> t1(1,2);
	test<string> t2("1.5","3.3");
	t1.output();
	t2.output();
	return 0;
}

命名空间

不同的开发成员的代码连桥时,把自己的代码放进明明空间里,用不同的明明空间,把所有的代码都包含进来。

namespace ns1
{
	class test
	{
	private:
		int m;
	public:
		test(int mm)
		{
			m=mm;
		}
		void output()
		{
			cout<<"m="<<m<<endl;
		}
	};
}
namespace ns2
{
	class test
	{
	private:
		int m;
	public:
		test(int mm)
		{
			m=mm;
		}
		void output()
		{
			cout<<"m="<<m<<endl;
		}
	};
}
ns1::test t1(10);
ns2::test t2(20);
t1.output();
t2.output();

虚函数:用基类的指针调用子类的同名函数 ⭐小题5分

定义父类指针,定义子类的同名函数,指向子类对象,最后实现的是父类的父类的函数。

用父类指针调用子类的同名函数,指向哪个类,就调用哪个同名函数。需要添加virtual函数。

using namespace std;

class test
{
protected:
	int m;
public:
	test(int mm)
	{
		m=mm;
	}
	virtual void output()
	{
		cout<<"m="<<m<<endl;
	}
};
class test1:public test
{
private:
	int n;
public:
	test1(int mm,int nn):test(mm)
	{
		n=nn;
	}
	virtual void output()
	{
		cout<<"n="<<n<<endl;
	}
}; 

int main()
{
	test1 t1(100,200);
	t1.output();
	//=============
//	test* p;
//	p=&t1;
//	//==============
//	p->output();
	return 0;
}

纯虚类,抽象类。基类没有具体实现,能派生出实际的函数,只是个架构。基类的指针,调用子类的同名函数,必须做成虚函数

class test
{
  protected:
    
  public:
    virtual void a1();
    virtual void a2();
    ...
    virtual void an();
};

异常处理:容错

最难发现的是逻辑错误,而逻辑错误都是难以发现的,抛不出来错误码,也捕获不了。

也可以用标准异常类

#include <iostream>
#include <conio.h>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

class test
{
private:
	double m,n;
public:
	test(double mm,double nn)
	{
		m=mm;n=nn;
	}
	void ave() throw(int)//定义函数,throw指明抛出的数据类型
	{
		if(n>1)
			cout<<m/n<<endl;
		else if(n==1)
			throw 1;
		else if(n==0)
			throw 0;
	}
};


int main()
{
	test t1(10,6),t2(10,1),t3(10,0);
	try//注意try和catch联系在一起地执行函数
	{
		t1.ave();
		t2.ave();
		t3.ave();
	}
	catch(int e)//捕获处理异常,参数是对抛出的整数码处理
	{
		if(e==1)
			cout<<"divided by 1"<<endl;
		if(e==0)
			cout<<"divided by 0"<<endl;
	}
	return 0;
}

数组越界检查。
类中有一个整数变量n和一个包括10个元素的整型数组a。在构造函数中给n赋值,当n超出数组上限时抛出异常信息码100(int)。
在主函数中建立一个类的对象,编写测试程序捕获其中的异常信息并给出相应提示(subscript out of range!)。

#include <iostream>
using namespace std;

class test
{
private:
	int n,i;
	int a[10];
public:
	test(int nn)throw(int)
	{
		n=nn;
		if(n>=10)
		{
			throw 100;//异常信息码 
		}
		else
		{
			for(i=0;i<n;++i)
			{
				a[i]=i+1;
			}
		}
	}
};

int main()
{
	try
	{
		test t(50);
	}
	catch(int error)
	{
		if(error==100)
		{
			cout<<"subscript out of range!"<<endl;
		}
	}
	return 0;
}

调试程序

#pragma once 如果有重复的头文件包含,自动忽略。

断点让程序停下来,查看此处变量的值。

定义一个调试开关,#define _DEBUG用这个变量来调试。 注释掉#define _DEBUG,就不会再输出调试信息。

#define _DEBUG
using namespace std;

class test
{
private:
	int m;
public:
	test(int mm)
	{
		m=mm;
#ifdef _DEBUG
		cout<<"test::test()"<<endl;
#endif	
	}
	void output()
	{	
		cout<<"m="<<m<<endl;
	}
	~test()
	{
#ifdef _DEBUG
		cout<<"test""~test()"<<endl;
#endif
	}
};


int main()
{
	test t(10);
	t.output();
#ifdef _DEBUG
	cout<<"========"<<endl;
#endif
	return 0;
}

7.2 QT

写好C++代码,移植程序,只要输入,输出。

QString qs;
qs=ui->lineEdit->text();
int n=qs.toInt();
//==============
test t(n);
n=t.square();
//==============
qs=qs.asprintf("%d",n);//把数n转换为字符串放到qs里面去
ui->lineEdit_2->setText(qs);

做法:

设计好页面,

移植类到头文件,只是函数声明。

移植类里面的函数的具体实现。

给响应函数。

实验就是给个C++代码,让你移植到 QT。

对于排序后的输出,一个文本框显然不够。需要用列表框。

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>
using namespace std;
class test
{
public://注意:这项修改了 
	vector<int>a;
	vector<int>::iterator p;
	int n,i;
public:
	test(int nn)
	{
		n=nn;
		srand(time(0));
		for(i=0;i<n;++i)
		{
			a.push_back(rand());
		}
	}
	static bool cmp(int n1,int n2)
	{
		return n1>n2;
	}
	void Sort()
	{
		sort(a.begin(),a.end(),cmp);
	}
	void browse()
	{
		for(p=a.begin();p!=a.end();++p)
		{
			cout<<*p<<endl;
		}
	}
};
int main() 
{
	test t(10);
	t.Sort();
	t.browse();
	return 0;
}c

8.1MFC

8.2复习课

真正的高手所有的存储都是字符串,其他的数据库需要转换,浪费时间。

底层就是这样看到的,只使用一个字段,然后解析,你用现成的体现不出别人的,实际工作的时候一个字段,毕业设计还是多个字段。

-学号1-姓名1-学号2-姓名2-学号3-姓名3-

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值