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

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;
}

 


总结: 

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

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

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

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

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










posted @ 2016-12-30 11:36  肥宝游戏  阅读(277)  评论(0编辑  收藏  举报