15.8.1
很简单 只需要多添加2个方法和一个状态就行 不过令我不解的是为什么需要将remote前向声明
tv.h
#ifndef TV_H
#define TV_H
#include <iostream>
using namespace std;
class Remote;//????这是为何 书上说如果声明为友元类就不需要前向声明了 如果没有这个不通过编译
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(void) { state = (state == On) ? Off : On; }
bool isOn(void) const { return On == state; }
bool volUp(void);
bool volDown(void);
void chanUp(void);
void chanDown(void);
void set_mode(void) { mode = (Antenna == mode) ? Cable : Antenna; }
void set_input(void) { input = (TV == input) ? DVD : TV; }
void setting(void) const;
void setstate(Remote &);
private:
int state;
int volume;
int maxchannel;
int channel;
int mode;
int input;
};
class Remote
{
private:
enum state{normal, interactive};
int mode;
int status;
public:
friend class Tv;
Remote(int m = Tv::TV, int state = normal) : mode(m), status(state){ }
bool volUp(Tv & t) { return t.volUp(); }
bool volDown(Tv & t) { return t.volDown(); }
void onOff(Tv & t) { t.onOff(); }
void chanUp(Tv & t) { t.chanUp(); }
void chanDown(Tv & t) { t.chanDown(); }
void set_chan(Tv & t, int c) { t.channel = c; }
void set_mode(Tv & t) { t.set_mode(); }
void set_input(Tv & t) { t.set_input(); }
void showmode(void) const
{
cout << "Now mode is:" << (status == normal ? "normal" : "interactive") << endl;
}
};
#endif
15.8.2
题意是让我们将使用logic_error派生出gmean与hmean且这2个类不需要存储值只需要支持what方法即可
error.h
#ifndef ERROR_H
#define ERROR_H
#include <stdexcept>
#include <iostream>
using namespace std;
class bad_hmean : public logic_error
{
public:
bad_hmean(const string & s = "bad_hmean(): invalid argument: a = -b") : logic_error(s) {}
};
class bad_gmean : public logic_error
{
public:
bad_gmean(const string & s = "bad_gmean(): arguments should be >= 0") : logic_error(s) {}
};
#endif
main.cpp
#include "error.h"
#include <cmath>
double hmean(double, double);
double gmean(double, double);
int main(void)
{
double x, y, z;
cout << "Enter two numbers: ";
while (cin >> x >> y)
{
try
{
z = hmean(x, y);
cout << "Harmonic mean of " << x << " and " << y
<< " is " << z << endl;
cout << "Geometric mean of " << x << " and " << y
<< " is " << gmean(x, y) << endl;
cout << "Enter next set of numbers <q to quit>: ";
}
catch (bad_hmean & bg)
{
cout << bg.what() << endl;
cout << "Try again.\n";
continue;
}
catch (bad_gmean & hg)
{
cout << hg.what() << endl;
cout << "Sorry, you don't get to play any more.\n";
break;
}
}
}
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 sqrt(a * b);
}
15.8.3
error.h
刚开始想的是logic_error分别派生2个类 写完发现没法调用显示函数 然后就改成多重派生结构
#ifndef ERROR_H
#define ERROR_H
#include <stdexcept>
#include <iostream>
using namespace std;
class bad_hmean : public logic_error
{
private:
double a;
double b;
public:
bad_hmean(const string & s, double n1, double n2) : logic_error(s), a(n1), b(n2) {}
virtual void show(void) const
{
cout << "bad_hmean() " << "a: " << a << " b: " << b << endl;
}
};
class bad_gmean : public bad_hmean
{
private:
double a;
double b;
public:
bad_gmean(const string & s, double n1, double n2) : bad_hmean(s, n1, n2) {}
virtual void show(void) const
{
cout << "bad_gmean() " << "a: " << a << " b: " << b << endl;
}
};
#endif
main.cpp
#include "error.h"
#include <cmath>
double hmean(double, double);
double gmean(double, double);
int main(void)
{
double x, y, z;
cout << "Enter two numbers: ";
while (cin >> x >> y)
{
try
{
z = hmean(x, y);
cout << "Harmonic mean of " << x << " and " << y
<< " is " << z << endl;
cout << "Geometric mean of " << x << " and " << y
<< " is " << gmean(x, y) << endl;
cout << "Enter next set of numbers <q to quit>: ";
}
catch (bad_hmean & bg)
{
bg.show();
cout << bg.what() << endl;
cout << "Try again.\n";
break;
}
}
}
double hmean(double a, double b)
{
if (a == -b)
throw bad_hmean("bad_hmean(): invalid argument: a = -b", a, b);
return 2.0 * a * b / (a + b);
}
double gmean(double a, double b)
{
if (a < 0 || b < 0)
throw bad_gmean("bad_gmean(): arguments should be >= 0", a, b);
return sqrt(a * b);
}
15.8.4
配合这个https://blog.csdn.net/xiyuan255/article/details/79224960看半天才看懂
原本的测试文件是分别捕获2种异常然后分别写出遇到异常之后的方法
现在的测试文件只需要捕获基类异常利用RTTI中dynamic_cast运算符来判断当前异常这个是否能转换到派生类异常中 能转换代表他本来就是派生类的异常 label_val()函数则有意义 不能转换就代表他是基类中的异常 此时就不需要调用label_val()
这样就符合了题意 每个try下只有一个catch
main.cpp
#include "sales.h"
int main(void)
{
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);
LabelSales 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 (5 == i % 6)
cout << endl;
}
cout << "Year = " << sales2.Year() << endl;
cout << "Label = " << sales2.Label() << endl;
for (i = 0; i <= 12; i++) {
cout << sales2[i] << ' ';
if (5 == i % 6)
cout << endl;
}
cout << "End of try block 1.\n";
} catch (Sales::bad_index & bad) {
cout << bad.what();
if (LabelSales::nbad_index * p = dynamic_cast<LabelSales::nbad_index *> (&bad))
cout << "Company: " << p->label_val() << endl;
cout << "bad index: " << bad.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 & bad) {
cout << bad.what();
if (LabelSales::nbad_index * p = dynamic_cast<LabelSales::nbad_index *> (&bad))
cout << "Company: " << p->label_val() << endl;
cout << "bad index: " << bad.bi_val() << endl;
}
cout << "Done.\n";
return 0;
}