【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
#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;
}
文件打开状态,不让操作。
#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-