C++ Primer Plus章节编程练习第十五章
1
题目
对Tv和Remote类做如下修改:
a.让它们互为友元;
b.在Remote类中添加一个状态变量成员,该成员描述遥控器是处于常规模式还是互动模式:
c.在Remote中添加一个显示模式的方法:
d.在Tv类中添加一个对Remote中新成员进行切换的方法,该方法应仅当TV处于打开状态时才能运行。
编写一个小程序来测试这些新特性。
题解
#include<iostream>
using namespace std;
//前向声明Tv
class Tv;
//Remote的声明
class Remote{
public:
enum State{Off,On};
enum{MinVal,MaxVal=20};
enum{Antenna,Cable};
enum{TV,DVD};
enum{Interactive,Regular}; //遥控模式
private:
int mode;
int remote_mode; //遥控模式
public:
friend class Tv; //TV是Remote的友元
Remote(int m=TV,int rm=Regular):mode(m),remote_mode(rm){}
bool volup(Tv &t);
bool voldown(Tv &t);
void onoff(Tv &t);
void chanup(Tv &t);
void chandown(Tv &t);
void set_chan(Tv &t,int c);
void set_mode(Tv &t);
void set_input(Tv &t);
void show()const;
};
class Tv{
private:
int state;
int volume;
int maxchannel;
int channel;
int mode;
int input;
public:
friend class Remote; //Remote是Tv的友元,Remote可以访问Tv的成员
enum State{Off,On};
enum{MinVal,MaxVal=20};
enum{Antenna,Cable};
enum{TV,DVD};
Tv(int s=Off,int mc=125):
state(s),volume(5),maxchannel(mc),channel(2),mode(Cable),input(TV){}
void onoff(){state=(state==On)?Off:On;}
bool ison()const {return state==On;}
bool volup();
bool voldown();
void chanup();
void chandown();
void set_mode(){mode=(mode==Antenna)?Cable:Antenna;}
void set_input(){input=(input==TV)?DVD:TV;}
void settings()const;
void change_remote_mode(Remote &rt);
};
bool Tv::volup(){
if(volume<MaxVal){
volume++;
return true;
}
else
return false;
}
bool Tv::voldown(){
if(volume>MinVal){
volume--;
return true;
}
else
return false;
}
void Tv::chanup(){
if(channel<maxchannel)
channel++;
else
channel=1;
}
void Tv::chandown(){
if(channel>1)
channel--;
else
channel=maxchannel;
}
void Tv::settings()const{
cout<<"TV is "<<(state==Off?"Off":"On")<<endl;
if(state==On){
cout<<"Volume setting = "<<volume<<endl;
cout<<"Channel setting = "<<channel<<endl;
cout<<"Mode = "
<<(mode==Antenna?"antenna":"cable")<<endl;
cout<<"Input = "
<<(input==TV?"TV":"DVD")<<endl;
}
}
void Tv::change_remote_mode(Remote &rt){
if(state==On)
rt.remote_mode=(rt.remote_mode==Remote::Regular?Remote::Interactive:Remote::Regular);
}
//Remote的方法定义,因为前置声明不知道tv的内容,所以remote的方法只声明,放在直到tv的定义之后在定义
bool Remote::volup(Tv &t){return t.volup();}
bool Remote::voldown(Tv &t){return t.voldown();}
void Remote::onoff(Tv &t){t.onoff();}
void Remote::chanup(Tv &t){t.chanup();}
void Remote::chandown(Tv &t){t.chandown();}
void Remote::set_chan(Tv &t,int c){t.channel=c;}
void Remote::set_mode(Tv &t){t.set_mode();}
void Remote::set_input(Tv &t){t.set_input();}
void Remote::show()const{
cout<<"Mode: "<<(mode==TV?"TV":"DVD")<<endl;
cout<<"Remote Mode: "
<<(remote_mode==Regular?"Regular":"Interactive")<<endl;
}
//测试函数
int main(){
Tv s42; //测试TV正常工作
cout<<"Initial settings for 42\" TV:\n";
s42.settings();
s42.onoff();
s42.chanup();
cout<<"\nAdjusted settings for 42\" TV:\n";
s42.settings();
Remote grey; //测试Remote正常工作
grey.set_chan(s42,10);
grey.volup(s42);
grey.volup(s42);
cout<<"\n42\" settings after using remote:\n";
s42.settings();
Tv s58(Tv::On);
s58.set_mode();
grey.set_chan(s58,28);
cout<<"\n58\" settings:\n";
s58.settings();
cout<<endl;
cout<<"Remote grey's setting:"<<endl;
grey.show();
s42.change_remote_mode(grey);
cout<<"after s42 changes the remote_mode of grey:"<<endl;
grey.show();
s58.onoff(); //关闭s58,则切换动作不会完成
s58.change_remote_mode(grey);
cout<<"s58 is Off!"<<endl;
cout<<"after s58 changes the remote_mode of grey:"<<endl;
grey.show();
return 0;
}
2
题目
修改程序清单15.11,使两种异常类型都是从头文件
题解
#include<iostream>
#include<cmath>
#include<string>
#include<stdexcept>
//异常类的声明和定义
//logic_error没有默认构造函数,所以直接构造即可
class bad_hmean:public std::logic_error{
public:
bad_hmean():std::logic_error("Except from hmean() with invalid arguments: a=-b\n"){}
std::string what(){return std::logic_error::what();}
};
class bad_gmean:public std::logic_error{
public:
double v1;
double v2;
bad_gmean():std::logic_error("Except from gmean() with invalid arguments: arguments shoulde be >=0\n"){}
std::string what(){return std::logic_error::what();}
};
double hmean(double a,double b);
double gmean(double a,double b);
int main(){
double x,y,z;
std::cout<<"Enter two numbers: ";
while(std::cin>>x>>y){
try{
z=hmean(x,y); //如果这条语句将会触发异常,则catch会捕获异常
std::cout<<"Harmonic mean of "<<x<<" and "<<y
<<" is "<<z<<std::endl;
std::cout<<"Geometric mean of "<<x<<" and "<<y
<<" is "<<gmean(x,y)<<std::endl;
std::cout<<"Enter next set of numbers <q to quit>: ";
}
catch(bad_hmean& bg){ //catch捕获的异常类型bad_hmean
std::cout<<bg.what();
std::cout<<"Try again.\n";
continue;
}
catch(bad_gmean& hg){ //catch捕获的异常类型bad_gmean
std::cout<<hg.what();
std::cout<<"Sorry, you don't get to play any more.\n";
break;
}
}
std::cout<<"Bye!\n";
return 0;
}
double hmean(double a,double b){
if(a==-b)
throw bad_hmean();
return 2.0*a*b/(a+b);
}
double gmean(double a,double b){
if(a<0||b<0)
throw bad_gmean();
return std::sqrt(a*b);
}
3
题目
这个练习与编程练习2相同,但异常类是从一个这样的基类派生而来的:它是从logic_error派生而来的,并存储两个参数值。异常类应该有一个这样的方法:报告这些值以及函数名。程序使用一个catch块来捕获基类异常,其中任何一种从该基类异常派生而来的异常都将导致循环结束。
题解
#include<iostream>
#include<cmath>
//异常类的基类声明和定义
class bad_except:public std::logic_error{
protected:
double v1,v2;
public:
bad_except(double a=0,double b=0,std::string er="Exception!!!"):
std::logic_error(er),v1(a),v2(b){}
virtual std::string what(){return std::logic_error::what();}
};
//两个异常类的定义和实现
class bad_hmean:public bad_except{
public:
bad_hmean(double a=0,double b=0,std::string er="Except from hmean() with invalid arguments: a=-b\n"):
bad_except(a,b,er){}
std::string what();
void who()const{std::cout<<"From hmean(), and two value: "<<v1<<", "<<v2<<std::endl;}
};
std::string bad_hmean::what(){
return bad_except::what();
}
class bad_gmean:public bad_except{
public:
bad_gmean(double a=0,double b=0,std::string er="Except from hmean() with invalid arguments: a=-b\n"):
bad_except(a,b,er){}
std::string what();
void who()const{std::cout<<"From gmean(), and two value: "<<v1<<", "<<v2<<std::endl;}
};
std::string bad_gmean::what(){
return bad_except::what();
}
double hmean(double a,double b);
double gmean(double a,double b);
int main(){
double x,y,z;
std::cout<<"Enter two numbers: ";
while(std::cin>>x>>y){
try{
z=hmean(x,y); //如果这条语句将会触发异常,则catch会捕获异常
std::cout<<"Harmonic mean of "<<x<<" and "<<y
<<" is "<<z<<std::endl;
std::cout<<"Geometric mean of "<<x<<" and "<<y
<<" is "<<gmean(x,y)<<std::endl;
std::cout<<"Enter next set of numbers <q to quit>: ";
}
catch(bad_hmean& bg){ //catch捕获的异常类型bad_hmean
std::cout<<bg.what();
bg.who();
break;
}
catch(bad_gmean& hg){ //catch捕获的异常类型bad_gmean
std::cout<<hg.what();
hg.who();
break;
}
}
std::cout<<"Bye!\n";
return 0;
}
double hmean(double a,double b){
if(a==-b)
throw bad_hmean(a,b);
return 2.0*a*b/(a+b);
}
double gmean(double a,double b){
if(a<0||b<0)
throw bad_gmean(a,b);
return std::sqrt(a*b);
}
4
题目
程序清单15.16在每个try后面都使用两个catch块,以确保nbad_index异常导致方法label_val()被调用。请修改该程序,在每个try块后面只使用一个catch块,并使用RTTI来确保合适时调用label_val()。
题解
#include<stdexcept>
#include<string>
#include<iostream>
class Sales{
public:
enum{MONTHS=12};
private:
double gross[MONTHS];
int year;
public:
class bad_index:public std::logic_error{
private:
int bi;
public:
explicit bad_index(int ix,const std::string &s="Index error in Sales object\n");
int bi_val()const{return bi;}
virtual ~bad_index()throw(){}
};
explicit Sales(int yy=0);
Sales(int yy,const double* gr,int n);
virtual ~Sales(){}
int Year()const{return year;}
virtual double operator[](int i)const;
virtual double &operator[](int i);
};
Sales::bad_index::bad_index(int ix,const std::string &s):std::logic_error(s),bi(ix){}
Sales::Sales(int yy){
year=yy;
for(int i=0;i<MONTHS;++i)
gross[i]=0;
}
Sales::Sales(int yy,const double *gr,int n){
year=yy;
int lim=(n<MONTHS)?n:MONTHS;
int i;
for(i=0;i<lim;++i)
gross[i]=gr[i];
for(;i<MONTHS;++i)
gross[i]=0;
}
double Sales::operator[](int i)const{
if(i<0||i>=MONTHS)
throw bad_index(i);
return gross[i];
}
double& Sales::operator[](int i){
if(i<0||i>=MONTHS)
throw bad_index(i);
return gross[i];
}
class LabeledSales:public Sales{
private:
std::string label;
public:
class nbad_index:public Sales::bad_index{
private:
std::string lbl;
public:
nbad_index(const std::string& lb,int ix,const std::string &s="Index error in LabeledSales object\n");
const std::string& label_val()const{return lbl;}
virtual ~nbad_index()throw(){}
};
explicit LabeledSales(const std::string& lb="none",int yy=0);
LabeledSales(const std::string& lb,int yy,const double *gr,int n);
virtual ~LabeledSales(){}
const std::string& Label()const{return label;}
virtual double operator[](int i)const;
virtual double& operator[](int i);
};
LabeledSales::nbad_index::nbad_index(const std::string&lb,int ix,const std::string&s):
Sales::bad_index(ix,s){
lbl=lb;
}
LabeledSales::LabeledSales(const std::string& lb,int yy):Sales(yy){
label=lb;
}
LabeledSales::LabeledSales(const std::string&lb,int yy,const double* gr,int n):
Sales(yy,gr,n){
label=lb;
}
double LabeledSales::operator[](int i)const{
if(i<0||i>=MONTHS)
throw nbad_index(Label(),i);
return Sales::operator[](i);
}
double &LabeledSales::operator[](int i){
if(i<0||i>=MONTHS)
throw nbad_index(Label(),i);
return Sales::operator[](i);
}
//测试函数
int main(){
using namespace std;
double vals1[12]={1220,1100,1122,2212,1232,2334,2884,2393,3302,2922,3002,3544};
double vals2[12]={12,11,22,21,32,34,28,29,33,29,32,35};
Sales sales1(2011,vals1,12);
LabeledSales sales2("Blogstar",2012,vals2,12);
cout<<"First try block:\n";
try{
int i;
cout<<"Year = "<<sales1.Year()<<endl;
for(i=0;i<12;++i){
cout<<sales1[i]<<' ';
if(i%6==5)
cout<<endl;
}
cout<<"Year = "<<sales2.Year()<<endl;
cout<<"Label = "<<sales2.Label()<<endl;
for(i=0;i<=12;++i){
cout<<sales2[i]<<' ';
if(i%6==5)
cout<<endl;
}
cout<<"End of try block 1.\n";
}
//bad由nbad派生而来,基类引用可以指向派生类,派生类通过RTTI转为基类(要保证安全性)
catch(Sales::bad_index& er){
if(typeid(er)==typeid(LabeledSales::nbad_index&)){ //根据实际的类型进行转换
cout<<dynamic_cast<LabeledSales::nbad_index&>(er).what();
cout<<"Company: "<<dynamic_cast<LabeledSales::nbad_index&>(er).label_val()<<endl;
cout<<"bad index: "<<dynamic_cast<LabeledSales::nbad_index&>(er).bi_val()<<endl;
}
if(typeid(er)==typeid(Sales::bad_index&)){
cout<<er.what();
cout<<"bad index: "<<er.bi_val()<<endl;
}
}
cout<<"\nNext try block:\n";
try{
sales2[2]=37.5;
sales1[20]=23345;
cout<<"End of try block 2.\n";
}
catch(Sales::bad_index& er){
if(typeid(er)==typeid(LabeledSales::nbad_index&)){
cout<<dynamic_cast<LabeledSales::nbad_index&>(er).what();
cout<<"Company: "<<dynamic_cast<LabeledSales::nbad_index&>(er).label_val()<<endl; //这个问题还未解决
cout<<"bad index: "<<dynamic_cast<LabeledSales::nbad_index&>(er).bi_val()<<endl;
}
if(typeid(er)==typeid(Sales::bad_index&)){
cout<<er.what();
cout<<"bad index: "<<er.bi_val()<<endl;
}
}
cout<<"done\n";
return 0;
}
Comments | NOTHING