《C++ Primer Plus(第六版)》(33)(第十五章 友元、异常和其他 编程题答案)

2016-12-30 19:50:47来源:CSDN作者:u012175089人点击

第七城市

15.8 编程练习

1.对Tv和Remote类做如下修改:

a.让他们互为友元;

b.在Remote类中添加一个状态变量成员,该成员描述遥控器是川渝常规模式还是互动模式;

c.在Remote中添加一个显示模式的方法;

d.在Tv类中添加一个队Remote中新成员进行切换的方法,该方法应仅当TV处于打开状态才能使用。

编写一个小程序来测试这些新特性。

Test.h

////  Test.h//  HelloWorld////  Created by feiyin001 on 16/12/21.//  Copyright (c) 2016年 FableGame. All rights reserved.//#ifndef _Test_H_#define _Test_H_#include <iostream>#include <string>#include <valarray>using namespace std;namespace FableGame{    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(){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;        bool changeInterAction(Remote& prev, bool interaction);    private:        int state;        int volume;        int maxchannel;        int channel;        int mode;        int input;    };    class Remote    {    private:        int mode;        bool interaction;//互动状态    public:        friend class Tv;        Remote(int m = Tv::TV):mode(m), interaction(false){}        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 showInteraction();    };}#endif

Test.cpp

////  Test.cpp//  HelloWorld////  Created by feiyin001 on 16/12/21.//  Copyright (c) 2016年 FableGame. All rights reserved.//#include "Test.h"#include <iostream>#include <cstdlib>using namespace std;using namespace FableGame;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;}bool Tv::changeInterAction(Remote& prev, bool interaction){    if ( state == Off ) {        return false;    }    prev.interaction = interaction;    return true;}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 Remote::showInteraction(){    if (interaction) {        cout << "Remote And TV is in interaction" << endl;    }    else{        cout << "Remote And TV is not in interaction" << endl;    }}
main.cpp

////  main.cpp//  HelloWorld////  Created by feiyin001 on 16/12/21.//  Copyright (c) 2016年 FableGame. All rights reserved.//#include <iostream>#include "Test.h"using namespace std;using namespace FableGame;int main(){    Tv s42;    Remote grey;    cout << "Initial settings for 42/" TV:/n";    s42.settings();    s42.changeInterAction(grey, true);    grey.showInteraction();    s42.onoff();    cout << "/nAdjusted settings for 42/" TV:/n";    s42.settings();    s42.changeInterAction(grey, true);    grey.showInteraction();        return 0;}

2.修改程序清单15.11,使用两种异常类型都是从头文件<stdexcept>提供的logic_error类派生出来的类。让每个what()方法都报告函数名和问题的性质。异常对象不用存储错误的参数值,而只需支持what()方法。

Test.h

////  Test.h//  HelloWorld////  Created by feiyin001 on 16/12/30.//  Copyright (c) 2016年 FableGame. All rights reserved.//#ifndef _Test_H_#define _Test_H_#include <iostream>#include <stdexcept>#include <string>using namespace std;namespace FableGame{    class bad_hmean: public logic_error    {    public:        explicit bad_hmean(const string& s):logic_error(s){}    };    class bad_gmean: public logic_error    {    public:        explicit bad_gmean(const string& s):logic_error(s){}    };}#endif
main.cpp

////  main.cpp//  HelloWorld////  Created by feiyin001 on 16/12/30.//  Copyright (c) 2016年 FableGame. All rights reserved.//#include <iostream>#include "Test.h"#include <cmath>using namespace std;using namespace FableGame;double hmean(double a, double b);//调和平均数double gmean(double a, double b);//几何平均数int main(){    double x,y,z;    cout << "Enter two numbers: /n";    while (cin >> x >> y) {        try        {            z = hmean(x, y);            cout << "Harmonic mean of " << x << " and " << y << " is " << z << endl;            z = gmean(x,y);            cout << "Geometric mean of " << x << " and " << y << " is " << z << endl;            cout << "Enter next set of numbers <q to quit>: ";        }        catch (bad_hmean & bg)        {            cout << bg.what();            cout << "Try again./n";            continue;        }        catch(bad_gmean & hg)        {            cout << hg.what();            cout << "Sorry, you don't get to play any more./n";            break;        }        cout << "Bye!/n";    }    return 0;}double hmean(double a, double b){    if (a == -b) {        throw bad_hmean("hmean() error: invalid arguments: a = -b/n");    }    return 2 * a * b/(a + b);}double gmean(double a, double b){    if (a < 0 || b < 0) {        throw bad_gmean("gmean() arguments should be >= 0/n");    }    return std::sqrt(a* b);}

3.这个练习与编程练习2相同,但异常类是从一个这样的基类派生而来的:它是从logic_error派生而来的,并且存储两个参数值。异常类应该有一个这样的方法:报告这些值以及函数名。程序使用一个catch来捕捉基类异常,其中任何一种从该基类异常派生而来的异常都将导致循环结束。

Test.h

////  Test.h//  HelloWorld////  Created by feiyin001 on 16/12/30.//  Copyright (c) 2016年 FableGame. All rights reserved.//#ifndef _Test_H_#define _Test_H_#include <iostream>#include <stdexcept>#include <string>#include <sstream>using namespace std;namespace FableGame{	string toStr(double val);	class bad_mean : public logic_error	{	public:		explicit bad_mean(const string& s, double a, double b);		virtual const char * what() const		{			return _what.c_str();		}	private:		double _a;		double _b;		string _what;	};}#endif
Test.cpp

////  Test.cpp//  HelloWorld////  Created by feiyin001 on 16/12/29.//  Copyright (c) 2016年 FableGame. All rights reserved.//#include "Test.h"#include <iostream> using namespace std;using namespace FableGame;FableGame::bad_mean::bad_mean(const string& s, double a, double b) :logic_error(s), _a(a), _b(b){ 	_what = logic_error::what();	_what = _what + "a:" + to_string(_a) + " b:" + to_string(_b) + "/n";}std::string FableGame::toStr(double val){ 	char buf[20];	sprintf_s(buf, "%f", val);	return string(buf);};
main.cpp

////  main.cpp//  HelloWorld////  Created by feiyin001 on 16/12/30.//  Copyright (c) 2016年 FableGame. All rights reserved.//#include <iostream>#include "Test.h"#include <cmath>using namespace std;using namespace FableGame;double hmean(double a, double b);//调和平均数double gmean(double a, double b);//几何平均数int main(){	double x, y, z;	cout << "Enter two numbers: /n";	while (cin >> x >> y) {		try		{			z = hmean(x, y);			cout << "Harmonic mean of " << x << " and " << y << " is " << z << endl;			z = gmean(x, y);			cout << "Geometric mean of " << x << " and " << y << " is " << z << endl;			cout << "Enter next set of numbers <q to quit>: ";		} 		catch (logic_error & bg)		{			cout << bg.what();			cout << "Sorry, you don't get to play any more./n";			break;		}		cout << "Bye!/n";	}	return 0;}double hmean(double a, double b){	if (a == -b) {		throw bad_mean("hmean() error: invalid arguments: a = -b/n", a, b);	}	return 2 * a * b / (a + b);}double gmean(double a, double b){	if (a < 0 || b < 0) {		throw bad_mean("gmean() arguments should be >= 0/n", a, b);	}	return std::sqrt(a* b);}

4.程序清单15.16在每个try后面都是用两个catch块,以确保nbad_index异常导致方法label_val()被调用。请修改该程序,在每个try块后面只使用一个catch块,并使用RTTI来确保合适时调用label_val().

原来的代码:

Test.h

////  Test.h//  HelloWorld////  Created by feiyin001 on 16/12/30.//  Copyright (c) 2016年 FableGame. All rights reserved.//#ifndef _Test_H_#define _Test_H_#include <iostream>#include <stdexcept>#include <string>#include <sstream>using namespace std;namespace FableGame{ 	class Sales	{	public:		enum{MONTHS = 12};		class bad_index : public 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);	private:		double gross[MONTHS];		int year;	};	class LabeledSales : public Sales	{	public:		class nbad_index : public Sales::bad_index		{		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(){}		private:			std::string lbl;		};		explicit LabeledSales(const string& lb = "none", int yy = 0);		LabeledSales(const 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);	private:		string label;	};}#endif
Test.cpp

////  Test.cpp//  HelloWorld////  Created by feiyin001 on 16/12/29.//  Copyright (c) 2016年 FableGame. All rights reserved.//#include "Test.h"#include <iostream> using namespace std;using namespace FableGame;FableGame::Sales::bad_index::bad_index(int ix, const std::string& s ):logic_error(s), bi(ix){}FableGame::Sales::Sales(int yy /*= 0*/){	year = yy;	for (int i = 0; i < MONTHS; ++i)	{		gross[i] = 0;	}}FableGame::Sales::Sales(int yy, const double* gr, int n){	year = yy;	int lim = (n < MONTHS) ? n : MONTHS;	for (int i = 0; i < MONTHS; ++i)	{		if (i < lim)		{			gross[i] = gr[i];		}		else		{			gross[i] = 0;		}	}}double FableGame::Sales::operator[](int i) const{	if (i < 0 || i >= MONTHS)	{		throw bad_index(i);	}	return gross[i];}double& FableGame::Sales::operator[](int i){	if (i < 0 || i >= MONTHS)	{		throw bad_index(i);	}	return gross[i];}FableGame::LabeledSales::nbad_index::nbad_index(const std::string& lb, int ix, const std::string& s):Sales::bad_index(ix,s){	lbl = lb;}FableGame::LabeledSales::LabeledSales(const string& lb /*= "none"*/, int yy /*= 0*/): Sales(yy){	label = lb;}FableGame::LabeledSales::LabeledSales(const string& lb, int yy, const double* gr, int n): Sales(yy, gr, n){	label = lb;}double FableGame::LabeledSales::operator[](int i) const{	if (i < 0 || i >= MONTHS)	{		throw nbad_index(Label(), i);	}	return Sales::operator[](i);}double & FableGame::LabeledSales::operator[](int i){	if (i < 0 || i >= MONTHS)	{		throw nbad_index(Label(), i);	}	return Sales::operator[](i);}
main.cpp

////  main.cpp//  HelloWorld////  Created by feiyin001 on 16/12/30.//  Copyright (c) 2016年 FableGame. All rights reserved.//#include <iostream>#include "Test.h"#include <cmath>using namespace std;using namespace FableGame; int main(){	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, 39, 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";	}	catch (LabeledSales::nbad_index& bad)	{		cout << bad.what();		cout << "Company: " << bad.label_val() << endl;		cout << "bad index: " << bad.bi_val() << endl;	}	catch (Sales::bad_index& bad)	{		cout << bad.what();		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 (LabeledSales::nbad_index& bad)	{		cout << bad.what();		cout << "Company: " << bad.label_val() << endl;		cout << "bad index: " << bad.bi_val() << endl;	}	catch (Sales::bad_index & bad)	{		cout << bad.what();		cout << "bad index: " << bad.bi_val() << endl;	}		cout << "done/n";	return 0;} 
修改代码:

////  main.cpp//  HelloWorld////  Created by feiyin001 on 16/12/30.//  Copyright (c) 2016年 FableGame. All rights reserved.//#include <iostream>#include "Test.h"#include <cmath>using namespace std;using namespace FableGame; int main(){	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, 39, 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";	} 	catch (Sales::bad_index& bad)	{		cout << bad.what();		cout << "bad index: " << bad.bi_val() << endl;		LabeledSales::nbad_index* bad2 = dynamic_cast<LabeledSales::nbad_index*>(&bad);		if (bad2)		{			cout << "Company: " << bad2->label_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();		cout << "bad index: " << bad.bi_val() << endl;		LabeledSales::nbad_index* bad2 = dynamic_cast<LabeledSales::nbad_index*>(&bad);		if (bad2)		{			cout << "Company: " << bad2->label_val() << endl;		}	}		cout << "done/n";	return 0;} 


总结: 

貌似越到后面,就经常出现了排版混乱的情况,不知道是原版的问题还是翻译本的问题。

程序例子也越来越抽象了,而且是说明的东西居多。

其实初学者,甚至学得好深入的人,接触的可能还是很少。

很多细节,只有在非常底层或者特定的应用中才会使用到。

或者,用到的时候,百度一下就可以了。










第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台