15.1
//tv.h
#ifndef TV_H_
#define TV_H_
#include<iostream>
class Remote;//不加该前项声明对void set_rstyle(Remote&r)函数进行定义时不能识别Remote类类型,且该前项声明必须位于Tv类声明前
class Tv
{
public:
friend class Remote;
enum {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() { 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 setting()const;
void set_rstyle(Remote&r);
private:
int state;
int volume;
int maxchannel;
int channel;
int mode;
int input;
};
class Remote
{
friend class Tv;//友元声明的位置无关紧要
public:
//friend class Tv;
enum {common,interac};
Remote(int m = Tv::TV, int s = common) :mode(m), style(s) {};
bool volup(Tv&t) { return t.volup(); };
bool voldown(Tv&t) { return t.voldown(); };
void show_style() { std::cout << (style == common ? "common" : "interac"); };
void onoff(Tv&t) { t.onoff(); };
void chanuo(Tv&t) { t.chanup(); };
void chandown(Tv&t) { t.chandown(); };
void set_mode(Tv&t) { t.set_mode(); };
void set_input(Tv&t) { t.set_input(); };
void set_chan(Tv&t, int c) { t.channel = c; };
private:
int mode;
int style;
};
#endif // !TV_H_
//tv.cpp
#include<iostream>
#include"tv.h"
bool Tv::volup()
{
if (volume == MaxVal)
return false;
volume++;
return true;
}
bool Tv::voldown()
{
if (volume == MinVal)
return false;
volume--;
return true;
}
void Tv::chanup()
{
if (channel < maxchannel)
channel++;
else
{
channel = 1;
}
}
void Tv::chandown()
{
if (channel > 1)
channel--;
else
{
channel = maxchannel;
}
}
void Tv::setting()const
{
using std::cout;
using std::endl;
cout << "TV is " << (state == off ? "off" : "on") << endl;
if (state == on)
{
cout << "Volume setting = " << volume << endl
<< "channel setting = " << channel << endl
<< "Mode= " << (mode == Antenna ? "antenna" : "cable") << endl
<< "Input= " << (input == TV ? "TV" : "DVD") << endl;
}
}
void Tv::set_rstyle(Remote&r)//由于Remote类定义在Tv之前,必须在Tv类声明前加前项声明,否则该函数将不能定义
{
if (state == on)
r.style = (r.style == Remote::common ? Remote::interac : Remote::common);
}//main.cpp
#include <iostream>
#include"tv.h"
using namespace std;
int main()
{
Tv s1;
cout << "Inital setting for Tv s1 \n";
s1.setting();
s1.chanup();
s1.set_input();
s1.onoff();
cout << "change for Tv s1\n";
Remote r1;
r1.set_chan(s1, 50);
cout << "Inital r1: " << endl;
r1.show_style();
s1.set_rstyle(r1);
cout << "\nChange for s1: " << endl;
r1.show_style();
return 0;
}
15.2
//15.2.h
#include<stdexcept>
using namespace std;
class bad_hmean :public logic_error
{
public:
explicit bad_hmean():logic_error("bad_hmean") {};//explicit表示禁止隐式类型转换
//logic_eror没有默认构造函数。如果不显示指出构造函数将不能使用派生类的默认构造函数,
//因为编译器自动生成的默认构造函数将为派生类自动调用基类默认构造函数,而该基类没有
//所以不能使用bad_hmean()调用默认构造函数,必须显式调用基类构造函数
const char* what() { return "bad agrguments to hmean, not allowed a= -b\n "; };
//只返回字符串的地址,并不输出该信息,在主程序中使用cout才能输出
};
class bad_gmean :public logic_error
{
public:
bad_gmean() :logic_error("bad_gmean") {};
const char*what() { return"bad agruments to gmean, not allowed a,b<0\n"; };
};
//main.cpp
#include <iostream>
#include"15.2.h"
//using namespace std;15.2.h中直接使用了std名称空间,包含该文件可以不加此条声明
double gmean(double x, double y);
double hmean(double x, double y);
int main()
{
double x, y,z;
cout << "enter two numbers: ";
while (cin>>x>>y)
{
try
{
z = hmean(x, y);//若hmean(x,y)不引发异常执行下面的语句,否则执行与之匹配的catch
cout << "harmonic mean of " << x << " and " << y
<< " is " << z<<endl;
cout << "Gemetric mean of " << x << " and " << y
<< " is " << gmean(x, y);
cout << "enter next two numbers<q to quit>: ";
}
catch (bad_hmean &bh)
{
cout<<bh.what();//what()返回字符指针,要使用cout才能输出
cout << "try again.\n";//将返回while继续输入,提示继续输入
continue;//引发bad_hmean异常后输出信息返回while继续输入
}
catch (bad_gmean &bg)
{
cout<<bg.what();
cout << "sorry,you don't get to play any more.\n";
break;//引发bad_gmean异常后输出信息退出while循环不能继续输入
}
}
return 0;
}
double hmean(double x, double y)
{
if (x == -y)
throw bad_hmean();
//bad_hmean()调用bad_hmean构造函数,创建一个bad_hmean对象
//throw将该异常类型返回导第一个可以与之匹配的try—catch块,并结束该函数
//由于throw返回的是bad_hmean对象,所以异常捕捉catch的异常类型应是
//bad_hmean对象的引用
return 2.0*x*y / (x*y);
}
double gmean(double x, double y)
{
if (x < 0 || y < 0)
throw bad_gmean();
return std::sqrt(x*y);
}
15.3
//15.3.h
#include<stdexcept>
using namespace std;
class bad_base :public logic_error
{
private:
double a, b;
public:
bad_base(const double x,const double y) :logic_error("bad_hmean"),a(x),b(y) {};
virtual void show()const;
};
class bad_hmean :public bad_base
{
public:
bad_hmean(const double x, const double y) :bad_base(x, y) {};
void show()const;
};
class bad_gmean :public bad_base
{
public:
bad_gmean(const double x,const double y) :bad_base(x,y) {};
void show() const;
};
void bad_base::show()const
{
cout<< "arguments x=" << a << ", y= " << b << endl;
}
void bad_hmean::show()const
{
bad_base::show();
cout << "bad_hmean exception,not allowed x=-y\n";
}
void bad_gmean::show()const
{
bad_base::show();
cout << "bad_gmean exception,a,b should be >0.\n";
}
//main.cpp
#include <iostream>
#include"15.3.h"
//using namespace std;15.2.h中直接使用了std名称空间,包含该文件可以不加此条声明
double gmean(double x, double y);
double hmean(double x, double y);
int main()
{
double x, y,z;
cout << "enter two numbers: ";
while (cin>>x>>y)
{
try
{
z = hmean(x, y);//若hmean(x,y)不引发异常执行下面的语句,否则执行与之匹配的catch
cout << "harmonic mean of " << x << " and " << y
<< " is " << z<<endl;
cout << "Gemetric mean of " << x << " and " << y
<< " is " << gmean(x, y);
cout << "enter next two numbers<q to quit>: ";
}
catch (bad_base &bh)//捕获所有基类异常
{
bh.show();//采用虚方法根据异常对象的不同调用不同的show()
//break;//所有基类异常派生的异常都导致循环结束
}
}
return 0;
}
double hmean(double x, double y)
{
if (x == -y)
throw bad_hmean(x,y);
return 2.0*x*y / (x*y);
}
double gmean(double x, double y)
{
if (x < 0 || y < 0)
throw bad_gmean(x,y);
return std::sqrt(x*y);
}
15.4
//15.4.h
#include<stdexcept>//包含logic_error类定义
#include<string>
using namespace std;
class Sales
{
public:
enum { MONTHS = 12 };
class bad_index :public logic_error//公有部分声明使Sales对象能够使用
{
private:
int bi;
public:
explicit bad_index(int ix,const string&s="Index error in Sales object\n") :logic_error(s) ,bi(ix){};
int bi_val()const { return bi; };
virtual ~bad_index() {};
};
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);//非const返回引用,可用于修改
private:
double gross[MONTHS];
int year;
};
class LabeleSales :public Sales
{
public:
class nbad_index :public Sales::bad_index
{
private:
string lbl;
public:
nbad_index(const string &lb, int ix, const string &s = "Index error in LableSales object\n")
:bad_index(ix, s), lbl(lb) {};
const string &label_val()const{ return lbl; }//公有内嵌类不能访问原类私有方法?
virtual ~nbad_index() {}
};
explicit LabeleSales(const string & lb = "none", int yy = 0);
LabeleSales(const string & lb, int yy, const double * gr, int n);
virtual ~LabeleSales() {}
const string & Label() const { return label; }
virtual double operator[](int i) const;
virtual double & operator[](int i);
private:
string label;
};
//15.4.cpp
#include<iostream>
#include"15.4.h"
//Sales method
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 i;
for (i = 0; i < n; 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];
}
//LabeleSales method
LabeleSales::LabeleSales(const string & lb , int yy)
:Sales(yy), label(lb) {};
LabeleSales::LabeleSales(const string & lb, int yy, const double * gr, int n)
:Sales(yy,gr, n), label(lb) {};
double LabeleSales::operator[](int i) const
{
if (i<0 || i>=MONTHS)
{
throw nbad_index(Label(),i);
}
return Sales::operator[](i);
//不能直接使用gross[i],他是Sales的私有成员公有继承不可访问,只能调用其公有方法
//注意重载函数的调用不是operator[i]
}
double & LabeleSales::operator[](int i)
{
if (i<0 || i>=MONTHS)//注意大于有等号
{
throw nbad_index(Label(), i);
}
return Sales::operator[](i);
}
//main.cpp
#include <iostream>
#include<typeinfo>
#include"15.4.h"
int main()
{
double vals1[12] =
{
12,11,22,15,32,15,
15,23,48,61,48,32
};
double vals2[12] =
{
45,16,13,48,56,26,
12,35,45,35,15,23
};
Sales s1(2011, vals1, 12);
LabeleSales ls1("Bligstar", 2012, vals2, 12);
cout << "First try block:\n";
try
{
int i;
cout << "Year = " << s1.Year() << endl;
for (i = 0; i < 12; i++)
{
cout << s1[i] << ' ';
if (i % 6 == 5)
cout << endl;
}
cout << "Year= " << ls1.Year() << endl;
cout << "Label = " << ls1.Label() << endl;
for (int i = 0; i <= 12; i++)
{
cout << ls1[i] << ' ';
if (i % 6 == 5)
cout << endl;
}
cout << "end of try block 1.\n";
}
catch (const Sales::bad_index&bad)
{
cout<<bad.what();//what方法返回一个字符串,构造函数将其设为错误类型
cout << "bad index: " << bad.bi_val();
if (typeid(LabeleSales::nbad_index) == typeid(bad))
{
const LabeleSales::nbad_index*p = static_cast<const LabeleSales::nbad_index*>(&bad);
//若要转换的对象是const类型转换后的类型也必须是const类型
cout << "Label: " << p->label_val() << endl;
}
}
try
{
ls1[20] = 37.5;
s1[2] = 23345;
cout << "End of try block 2.\n";
}
catch (Sales::bad_index&b)
{
cout << b.what();
cout << "bad index: " << b.bi_val()<<endl;
if (typeid(LabeleSales::nbad_index) == typeid(b))
{
LabeleSales::nbad_index*p = static_cast<LabeleSales::nbad_index*>(&b);
cout << "Label: " << p->label_val() << endl;
}
}
return 0;
}