1.问题:怎么处理异常?
思路:计算机中具体过程如何???
代码:#include
using namespace std;
class Parent{};
class Child:public Parent{};
int func()
{
try{
cout<<"good"<
throw"如来神掌";//char const *
cout<<"morning"<
catch(const Child& e){
//------
}
catch(const Parent& e){
//------
}
catch(const char* e){// 严格类型匹配//const 和char可以交换顺序
cout<<" 用九阳神功化解"<
catch(long e){
cout<<"long"<
// catch(...){
// cout<<"unknown exception"<
cout<<"bye"<
int main()
{
try{
func();
}catch(...){
cout<<" 未知异常"<
cout<<"main"<
解释:异常这部分是对前面所有知识的异常部分的总结综合!
1.异常:exception,是一个头文件的名字,也是一个类名,只有一个虚函数string what(); 表示对异常
行为的描述。
不常发生但又不可避免的情况叫做发生异常,但异常不是错误bug。
处理异常3步走:
1.1.try{可能出现异常的代码或者是调用可能出现异常的函数}
1.2.if(发现异常情况)
throw 数据;数据可以为任何类型
1.3.catch( 类型1 变量名){ 捕获异常数据
}catch( 类型2 变量名){}******
集中处理不常见的情况
catch(...){可以捕获任何异常的数据,但不知道如何发生异常了}
2.异常声明
标准异常exception what()
catch(const exception& e){
cout<
思路:有默认的,逐个成员复制
class A{
char* p;
public:
A(const char* s){
p=new char[strlen(s)+1];// 加1是给‘/0’
strcpy(p,s);// 才是复制字符串,而不是p=s;只有C++风格的string 时才能用赋值表示。
}
代码:#include
using namespace std;
class Name{
char* p;
public:
Name(const char* s){
p=new char[strlen(s)+1];
strcpy(p,s);
}
~Name(){
cout<<"free"<<(void*)p<
}
Name(const Name& n){// 拷贝函数//避免空间重复释放
p=new char[strlen(n.p)+1];
strcpy(p,n.p);
}
};
int main()
{
Name n1("chenzq");
Name n2(n1);//拷贝构造函数调用
}
解释:拷贝构造函数:对以前有何补充???
1.A a1; A a2(a1); 或A a2=a1;( 变量初始化,不是赋值)
2. 形参非引用,实参是对象
3. 返回类型非引用,return 对象;
如果类中有指针成员指向动态内存,这时候才需要对指针特别对待。
3.问题:用1/2+1/3=5/6,解释运算符重载
思路1:在前程序基础上,用运算符重载cout代替output函数;
在这个程序基础上,添加运算符重载+代替add函数;
思路2:把外部函数直接调入类中,并在操作符重载中减少一个形参
代码1:#include
using namespace std;
class F{
int n;
int d;
public:
F(int n,int d):n(n),d(d){}
friend F add(const F& f1,const F& f2);
friend F operator+(const F& f1,const F& f2);//这是在修改部分基础上,再添加代码
//friend ostream& output(ostream& os,const F& f);
friend ostream& operator<<(ostream& os,const F& f);
};
F add(const F& f1,const F& f2)
{
int d=f1.d*f2.d;
int n=f1.n*f2.d+f1.d*f2.n;
return F(n,d);
}
F operator+(const F& f1,const F& f2)//这是在修改部分基础上,再添加代码//遇到+和F类两个对象,
就调用本函数,返回对象
{
int d=f1.d*f2.d;
int n=f1.n*f2.d+f1.d*f2.n;
return F(n,d);
}
/*ostream& output(ostream& os,const F& f)
{
os<
}*/
ostream& operator<<(ostream& os,const F& f) //这是修改部分,注释代码是原来程序的//遇到cout和
F类对象,就调用本函数
{
os<
}
int main()
{
F f1(1,2),f2(1,3); //这是修改部分,注释代码是原来程序的
// output(cout,f1)<<"+";
// cout<
// output(cout,add(f1,f2))<
代码2:#include
using namespace std;
class F{
int n;
int d;
public:
F(int n=0,int d=1):n(n),d(d){}
friend ostream& operator<<(ostream& os,const F& f){//为什么必须是友元???
os<
}
F operator+(const F& f)const{
int n1=n*f.d+d*f.n;
int d1=d*f.d;
return F(n1,d1);
}
};
int main()
{
F f1(1,2),f2(1,3);
cout<
解释:运算符重载:前一程序是解释友元概念,本程序其改写版(根据添加代码的需要),添加版体现运
算符重载
自行规定运算符如何处理各个操作数,以及用什么当运算结果
要求:至少有一个操作数是你自定义类型的
关键字:operator@
4.问题:分数分子分母颠倒
思路:实参对象的分子分母换位返回即可
代码:#include
using namespace std;
class F{
int n;
int d;
public:
F(int n=0,int d=1):n(n),d(d){}
friend ostream& operator<<(ostream& os,const F& f){
os<
}
friend F operator~(const F& f){//换位返回
return F(f.d,f.n);
}
bool operator!(){
if(n==0) return true;
else return false;
}
};
int main()
{
F f1(2,3);
cout<<"f1="<
cout<<"f1 is false"<
cout<<"f1 is true"<
解释:单目运算符-----
1.类的基本格式:
class 类名{
数据成员1(可省,就可不执行);
...
数据成员2(可省,就可不执行);
public:
构造函数(不可省,函数体可为空);
...
析构函数(可省,只是看不见,却必执行);
};
5.问题:分数前++和后++,前--后--
思路:无
代码:#include
using namespace std;
class F{
int n;
int d;
public:
F(int n=0,int d=1):n(n),d(d){}
friend ostream& operator<<(ostream& os,const F& f){
os<
}
F& operator++(){
n+=d;
return *this;//*this 表示当前对象,而this只是一个指针
}
F operator++(int){//int 称为哑元//旧值不需要开辟新的空间,所以用引用。
F old(*this); //对象声明。有时和函数很类似哦。。。吼吼
operator++();
return old;
}
/*//可与友元替换,比较结果如何?一样。为什么改成友元???
F& operator--(){
n-=d;
return *this;
}
F operator--(int){
F old(*this);
operator--();
return old;
}
*/
friend F& operator--(F& f){
f.n-=f.d;
return f;
}
friend F operator--(F& f,int){//在f4--时用,为什么???
F old(f);
--f;//operator--(f);
return old;
}
};
int main()
{
F f1(2,3),f2(2,3);
cout<<"++f1="<<++f1<
cout<<"f1="<
cout<<"f2="<
cout<<"--f3="<<--f3<
解释:无
6.问题:对象类型转换
思路:无
代码:#include
using namespace std;
class F{
int n;
int d;
public:
F(int n=0,int d=1):n(n),d(d){}
friend ostream& operator<<(ostream& os,const F& f){
os<
}
operator double(){
return (double)n/d;
}
operator bool(){
return n!=0;
}
};
int main()
{
F f1(1,2),f2(1,3);
cout<<(double)f1<
解释:类型转换运算符只能写成成员函数,而不能写成友元函数
7.问题:输入输出两分数
思路:无
代码:#include
using namespace std;
class F{
int n;
int d;
public:
F(int n=0, int d=1):n(n),d(d){}
friend ostream& operator<<(ostream& os, const F& f){输出时用
os << f.n << '/' << f.d;
return os;
}
friend istream& operator>>(istream& is, F& f){//输入时用
char ch;
is >> f.n >> ch >> f.d;//输入没有‘/’,即输入分数时,要一并输入‘/’号或者其他字符
return is;
} //输入千万不能加const
};
int main()
{
F f1, f2;
cout << "input 2 fractions:";
cin >> f1 >> f2;
cout << "f1=" << f1 << endl;
cout << "f2=" << f2 << endl;
}
解释:无
8.问题:赋值运算符函数例程
思路:在有指针函数指向动态内存时,往往时三大函数同时写析构函数、构造函数、拷贝构造函数
代码:#include
using namespace std;
#include
class Name{
char* p;
public:
Name(const char* s){
p=new char[strlen(s)+1];
strcpy(p,s);
}
~Name(){
cout<<"free"<<(void*)p<
}
Name(const Name& n){//调用下面的函数
p=NULL;//new char[strlen(n.p)+1];
operator=(n);//strcpy(p,n.p);
}
Name& operator=(const Name& n){//相对于拷贝构造函数例程,添加部分
if(this!=&n){
delete[] p;//释放旧空间
p=new char[strlen(n.p)+1];//开辟新空间
strcpy(p,n.p);//复制
}
return *this;
}
};
int main()
{
Name n1("chenzq");
Name n2(n1);
n2=n1;//相对于拷贝构造函数例程,添加部分
}
解释:1.operator()(){} 函数对象 可以试试;凡是操作数据的运算符都可以重载,不能重载的运算符:
./.*/?:/::/sizeof/#/##;,需要掌握的:=/[]/类型转换 其它随意,要符合运算符本身的运用习惯。
9.问题:输入字符,整型和其他类型分开保存
思路:1.循环:输入n;判断是否有'/n',' ','/t',有则跳出循环;判断是否不等于cin,不等:清除读
取失败,相等,跳出循环
2.保存剩余的字符
代码:#include
using namespace std;
int main()
{
int n;
for(;;){
cout<<"input an integer:";
cin>>n;
if(cin.peek()!='/n'&&cin.peek()!=' '&&cin.peek()!='/t'){
cout<<" 不是个干净的整数"<
}
cout<<"n="<
cout<<" 读取失败!"<
cin.ignore(100,'/n');// 代表一次抛掉几个字符,默认是1个
}
else
break;
}
char remain[80];
cin>>remain; //保存剩余的字符
cout<<"remain="<
补充:尝试输入100.45,1234safdgsl;dke,1234 safdgsl;dke,abc几个字符
解释:cin.clear();清除
cin.ignore(100,'/n');抛掉多少个字符
cin.peek();只看不取走,返回ACSII码
cin.get();看并且取走
10.问题:输出指定文件内容,统计字符数
思路:根据文件名变成数据流->循环:对每个字符存储到变量中,输出,直到数据流输出完(用while也
可)->关闭文件
代码:#include
using namespace std;
#include
int main()
{
char name[100];
cout<<"input filename:";
cin>>name;
ifstream fin(name);//1.相当于:ifstream fin;fin.open("文件名");//不常用的//ifstream是input
file stream缩写
if(!fin){// 相当于if(!fin.is_open())// 检测函数是否打开
cerr<<"not exist"<
}
char ch;
int cnt=0;
for(;;){//不断执行2.和3.步骤
ch=fin.get();//2.获得字符并存储
//cout<<(char)fin.get();//fin>> 会跳过某些字符
if(!fin){//4.相当于if(!fin.eof())// 检测是否超越了末尾
fin.clear();//fin是file input的缩写
break;
}
cout<
}
fin.close();// 关闭后释放资源
cout<<"length:"<
解释:I/O :input/output stream 流:一系列字符(字节)
流:有序的一次传递,可以缓冲、重定向
cin/cout 可以缓冲也可以重定向
/cerr :不缓冲不重定向
/clog:可以缓冲不重定向
类型:cin istream
cout/cerr/clong ostream
11.问题:输入指定文件,输出结果,并输出结果到指定文件
思路:输入指定文件->判断是否合法->功能->关闭输入文件->输出变量->创建输出文件->判断能否创建->
输出变量->关闭输出文件
代码:#include
using namespace std;
#include
int main()
{
int sum=0;
int one;
int cnt=0;
//ifstream fin("data"); //可与下4行替换
char name[100];
cout<<"input filename:";
cin>>name;
ifstream fin(name);
if(!fin){
cout<<" 找不到文件data"<
}
while(fin>>one){//结果还是fin//核心功能???
sum+=one;
++cnt;
}
fin.clear();
fin.close();
cout<<"sum="<
if(!fout){
cout<<" 无法创建文件result"<
}
fout<<" 总和为"<
}
解释:无
12.问题:输入字符,将其输出
思路:cin.get(变量):1.只能接受输入5个字符,并输出
2.for结构可以接受无数个字符,并输出
3.while结构可以接受无数个字符,并输出
代码1:#include
using namespace std;
int main()
{
char a,b,c,d,e;
cout<<"input some chars:";
cin.get(a).get(b);
cin.get(c);
cin.get(d);
cin.get(e);
cout<<"a=["<cout<<"b=["<cout<<"c=["<
代码2:#include
using namespace std;
int main()
{
char ch;
cout<<"input some text:/n";
for(;;){//可替换为while结构
cin.get(ch);
if(cin){//合法
cout<
break;//跳出无线循环
}
}
}
代码3:#include
using namespace std;
int main()
{
char ch;
cout<<"input some text:/n";
while(cin.get(ch)){//可替换为for结构
cout.put(ch);// cout<
break;
}
}
解释:>> 格式化输入 键盘上输入的是个字符序列 而到程序中就成各种类型变量
会自动处理格式的问题 cin>>各种类型变量
char ch; in.get(ch) 带回的就是当前对象
13.问题:编译后,输入“./a.out 文件名”,可得到带行标识的输出的指定文件内容
思路:1.判断命令是否有参数,若无不执行2和3步
2.读入文件名是否合法,如不合法,不执行3步
3.逐行读入文件内容,并输出,直到结束
4.关闭文件
代码:#include
using namespace std;
#include
#include
int main(int argc,char* argv[])//类似于命令行的输入
{
if(argc!=2){//如果命令后无参数
cout<<*argv<<"filename"<
}
ifstream fin(argv[1]);//输入argv[1]内容
if(!fin){//如果不合法
cout<<"error!"<
}
string line;
for(int i=1; ;i++){
getline(fin,line);//string头文件包含函数;按行从文件输入
if(!fin) break;//文件结束跳出
cout<}
fin.close();
}
补充:尝试执行:wc 文件名
解释:in.getline( 字符数组名,数组大小)有长度限制
getline(in,string 对象)没有长度的限制,一般用此用法
14.问题:读取passwd文件,逐项内容输出
思路:前面的基础上,分别读取,存储和输出
代码:#include
using namespace std;
#include
#include
int main()
{
string name,pass,id,gid,comm,dir,shell;
ifstream fin("/etc/passwd");
if(!fin){
cout<<"I can't open it."<
}
for(int i=0;i<5;i++){// 读取5行
getline(fin,name,':');//识别':',此为判断标志读取内容
getline(fin,pass,':');//识别':',此为判断标志读取内容
getline(fin,id,':'); //识别':',此为判断标志读取内容
getline(fin,gid,':'); //识别':',此为判断标志读取内容
getline(fin,comm,':'); //识别':',此为判断标志读取内容
getline(fin,dir,':');//识别':',此为判断标志读取内容
getline(fin,shell,':'); //识别':',此为判断标志读取内容
cout<<"name:/t"<
fin.close();
}
解释:在某些UNIX系统中,如果没有相应权限,将不能打开passwd文件,即本程序不能完全执行。
15.问题:输入大于9的数值,输出
思路:
代码:#include
using namespace std;
int main()
{
int n;
char ch;//应该是单个字符???
cout<<"input an integer(num>9):";
cin.get(ch); //为什么大费周章的用这个函数???
if(ch>='0'&&ch<='9')//如果注释这部分会是什么样的结果?
cin.putback(ch);
cin>>n;
cout<<"n="<
解释:cin.peek()
cin.putback( 字符)退回的字符必须是刚才用get读走的字符
putback 不与peek一起用
16.问题:保存数的参数到文件,再从文件根据参数,输出数
思路1:读入一个整型数,存到sav文件中其内存地址和字节数
思路2:读入sav文件内容,输出指定数
代码1:#include
#include
using namespace std;
int main()
{
int n=123456789;
ofstream fout("sav");// 写到sav 文件中
if(!fout){
cout<<"error!"<
}
fout.write((char*)&n,sizeof(n));//write 总是带个类型转换
fout.close();
}
代码2:#include
#include
using namespace std;
int main()
{
int n=0;
ifstream fin("sav");
if(!fin){
cout<<"file sav not found"<
}
fin.read((char*)&n,sizeof(n));
fin.close();
cout<<"n="<
解释:fin.read(内存地址,字节数) 一般用来读文件。从文件中把数据读逐个字节读出来,原样逐字节
放到指定地址开始的内存中
fout.write( 内存地址,字节数) 把从指定内存地址开始指定字节数的内存数据逐字节写到文件中
read和write 根本不关心数据类型,只关心在内存里几个字节数
17.问题:用命令格式复制文件内容到指定文件
思路:判断读入文件和输出文件是否合法->拷贝文件内容到指定文件->关闭读入和输出文件
代码:#include
#include
using namespace std;
int main(int argc,char* argv[])
{
if(argc!=3){
cout<<*argv<<"oldfile newfile"<
}
ifstream fin(argv[1]);
ofstream fout(argv[2]);
if(!fin||!fout){
cout<<"error!"<
}
char buf[1000];
do{//该部分为核心功能语句
fin.read(buf,1000); //每次读取1000个单元
fout.write(buf,fin.gcount());
}while(fin);
fin.clear();
fin.close();
fout.close();
}
解释:别把指针保存到文件中,它会有潜在的危险
fin.gcount() 表示这次read 读取到了多少字符
18.问题:拷贝字符串
思路:判断创建输出文件->输入字符串->输出到指定文件->关闭输出文件
代码:#include
#include
#include
using namespace std;
int main()
{
ofstream fout("log.txt",ios::app);//ios::app 表示追加,否则就默认清空原有的内容。
if(!fout){
cout<<"error!"<
}
cout<<"input some text:";
string str;
getline(cin,str);
fout<
}
解释:上一程序可以此拷贝方法重写
19.问题:不能编译???
思路:
代码:#include
#include
#include
using namespace std;
int main()
{
fstream fio("file");//为什么调不出fstream???
if(!fio){
cout<<"error!"<
}
char buf[10];
fio.read(buf,10);
cout.write(buf,10);
cout<
swap(buf[i],buf[i+5]);
fio.seekp(0);// 指定往哪写
fio.write(buf,10);
fio.seekg(10);// 表示到哪里去读,0表示第一个位置
char ch;
fio.get(ch);
cout<<"ch="<
}
解释:如果又要读要写,就用fstream
20.问题:指定宽度输出内容
思路:指定宽度,指定fill;不指定宽度;指定宽度,不写指定fill;
代码:#include
using namespace std;
int main()
{
cout.width(10);
cout.fill('*'); //为什么是7个???
cout<<123<
cout<<123<
解释:width() 指定宽度是一次性的,如果指定的宽度的小于输入的宽度,输出时是需要的宽度不会截取
21.问题:指定小数位
思路:指定位数并四舍五入,指定小数后位数,指定数总位数
代码:#include
using namespace std;
int main()
{
double d=12345.6789;
cout<<"d="<
cout<<"d="<
cout.setf(ios::fixed);//表示小数点后的位数
cout<<"d="<
cout<<"d="<
解释:指定小数的精度:precision()
22.问题:数值不同表示
思路:无
代码1:#include
using namespace std;
int main()
{
cout<
代码2:#include
using namespace std;
#include
int main()
{
cout<
解释:输出控制标志和控制符