Friends, Exceptions, and More

Friends



// tv.h -- Tv and Remote classes

#ifndef _TV_H_
#define _TV_H_
enum Bool {False, True};	// or use built-in Bool type, if available

class Tv
{
public:
	friend class Remote;	// Remote can access Tv private parts
	enum State{Off, On};
	enum {MinVal,MaxVal = 20};
	enum {Antenna, Cable};
	enum {TV, VCR};

	Tv(State s = Off, int mc = 100) : state(s), volume(5),
		maxchannel(mc), channel(2), mode(Cable), input(TV) {}
	void onoff() {state = (state == On)? Off : On;}
	Bool ison() {return state == On ? True : False;}
	Bool volup();
	Bool voldown();
	void chanup();
	void chandown();
	void set_mode() {mode = (mode == Antenna)? Cable : Antenna;}
	void set_input() {input = (input == TV)? VCR : TV;}
	void settings();		// display all settings
private:
	State state;		// on or off
	int volume;		// assumed to be digitized
	int maxchannel;
	int channel;
	int mode;			// broadcast or cable
	int input;			// TV or VCR
};

class Remote
{
private:
	int mode;	// controls TV or VCR
public:
	Remote(int m = Tv::TV) : mode(m) {}
	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();}
};
#endif


// tv.cpp -- methods for the Tv class (Remote methods are inline)

#include <iostream.h>
#include "tv.h"

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()
{
	cout << "TV is " << (state == Off? "Off\n" : "On\n");
	if (state == On)
	{
		cout << "Volume setting = " << volume << "\n";
		cout << "Channel setting = " << channel << "\n";
		cout << "Mode = "
			<< (mode == Antenna? "antenna\n" : "cable\n");
		cout << "Input = "
			<< (input == TV? "TV\n" : "VCR\n");
	}
}



//use_tv.cpp

#include <iostream.h>
#include "tv.h"

int main(void)
{
	Tv s20;
	cout << "Initial settings for 20\" TV:\n";
	s20.settings();
	s20.onoff();
	s20.chanup();
	cout << "\nAdjusted settings for 20\" TV:\n";
	s20.settings();

	Remote grey;

	grey.set_chan(s20, 10);
	grey.volup(s20);
	grey.volup(s20);
	cout << "\n20\" settings after using remote:\n";
	s20.settings();

	Tv s27(Tv::On);
	s27.set_mode();
	grey.set_chan(s27,28);
	cout << "\n27\" settings:\n";
	s27.settings();

	return 0;
}



// tvfm.h -- Tv and Remote classes using a friend member

#ifndef _TVFM_H_
#define _TVFM_H_

enum Bool {False, True};

class Tv; 	// forward declaration

class Remote
{
public:
	enum State{Off, On};
	enum {MinVal,MaxVal = 20};
	enum {Antenna, Cable};
	enum {TV, VCR};
private:
	int mode;
public:
	Remote(int m = TV) : mode(m) {}
	Bool volup(Tv & t);			// prototype only
	Bool voldown(Tv & t);
	void onoff(Tv & t) ;
	void chanup(Tv & t) ;
	void chandown(Tv & t) ;
	void set_mode(Tv & t) ;
	void set_input(Tv & t);
	void set_chan(Tv & t, int c);

};

class Tv
{
public:
	friend void Remote::set_chan(Tv & t, int c);
	enum State{Off, On};
	enum {MinVal,MaxVal = 20};
	enum {Antenna, Cable};
	enum {TV, VCR};

	Tv(State s = Off, int mc = 100) : state(s), volume(5),
		maxchannel(mc), channel(2), mode(Cable), input(TV) {}
	void onoff() {state = (state == On)? Off : On;}
	Bool ison() {return state == On ? True : False;}
	Bool volup();
	Bool voldown();
	void chanup();
	void chandown();
	void set_mode() {mode = (mode == Antenna)? Cable : Antenna;}
	void set_input() {input = (input == TV)? VCR : TV;}
	void settings();
private:
	State state;
	int volume;
	int maxchannel;
	int channel;
	int mode;
	int input;
};

// Remote methods as inline functions
inline Bool Remote::volup(Tv & t) { return t.volup();}
inline Bool Remote::voldown(Tv & t) { return t.voldown();}
inline void Remote::onoff(Tv & t) { t.onoff(); }
inline void Remote::chanup(Tv & t) {t.chanup();}
inline void Remote::chandown(Tv & t) {t.chandown();}
inline void Remote::set_mode(Tv & t) {t.set_mode();}
inline void Remote::set_input(Tv & t) {t.set_input();}
inline void Remote::set_chan(Tv & t, int c) {t.channel = c;}
#endif


Nested Classes



// queuetp.h -- queue template with a nested class

#include "booly.h"

template 
class QueueTP
{
private:
	enum {Q_SIZE = 10};
	// Node is a nested class definition
	class Node
	{
	public:
		Item item;
		Node * next;
		Node(const Item & i):item(i), next(0){ }
	};
	Node * front;		// pointer to front of Queue
	Node * rear;		// pointer to rear of Queue
	int items;			// current number of items in Queue
	const int qsize;	// maximum number of items in Queue
	QueueTP(const QueueTP & q) : qsize(0) {}
	QueueTP & operator=(const QueueTP & q) { return *this; }
public:
	QueueTP(int qs = Q_SIZE);
	~QueueTP();
	Bool isempty() const
	{
		return items == 0 ? True : False;
	}
	Bool isfull() const
	{
		return items == qsize ? True : False;
	}
	int queuecount() const
	{
		return items;
	}
	Bool enqueue(const Item &item);	// add item to end
	Bool dequeue(Item &item);	// remove item from front
};

// QueueTP methods
template 
QueueTP::QueueTP(int qs) : qsize(qs)
{
	front = rear = NULL;
	items = 0;
}

template 
QueueTP::~QueueTP()
{
	Node * temp;
	while (front != NULL)	// while queue is not yet empty
	{
		temp = front;		// save address of front item
		front = front->next;// reset pointer to next item
		delete temp;		// delete former front
	}
}

// Add item to queue
template 
Bool QueueTP::enqueue(const Item & item)
{
	if (isfull())
		return False;
	Node * add = new Node(item);	// create node
	if (add == NULL)
		return False;		// quit if none available
	items++;
	if (front == NULL)		// if queue is empty,
		front = add;		// place item at front
	else
		rear->next = add;	// else place at rear
	rear = add; 			// have rear point to new node
	return True;
}

// Place front item into item variable and remove from queue
template 
Bool QueueTP::dequeue(Item & item)
{
	if (front == NULL)
		return False;
	item = front->item;		// set item to first item in queue
	items--;
	Node * temp = front;	// save location of first item
	front = front->next;	// reset front to next item
	delete temp;			// delete former first item
	if (items == 0)
		rear = NULL;
	return True;
}



// nested.cpp -- use queue having a nested class

// compile along with stng2.cpp
#include <iostream.h>
#include "strng2.h"
#include "queuetp.h"

int main(void)
{

	QueueTP cs(5);
	String temp;

	while(!cs.isfull())
	{
		cout << "Please enter your name. You will be "
				"served in the order of arrival.\n"
				"name: ";
		cin >> temp;
		cs.enqueue(temp);
	}
	cout << "The queue is full. Processing begins!\n";

	while (!cs.isempty())
	{
		cs.dequeue(temp);
		cout << "Now processing " << temp << "...\n";
	}
	return 0;
}



Exceptionss



//error1.cpp -- use the abort() function

#include <iostream.h>
#include <stdlib.h>
double hmean(double a, double b);

int main(void)
{
	double x, y, z;

	cout << "Enter two numbers: ";
	while (cin >> x >> y)
	{
		z = hmean(x,y);
		cout << "Harmonic mean of " << x << " and " << y
			<< " is " << z << "\n";
		cout << "Enter next set of numbers : ";
	}
	cout << "Bye!\n";
	return 0;
}

double hmean(double a, double b)
{
	if (a == -b)
	{
		cout << "untenable arguments to hmean()\n";
		abort();
	}
	return 2.0 * a * b / (a + b);
}



//error2.cpp __ return an error code

#include <iostream.h>
#include <float.h>
#include "booly.h"

Bool hmean(double a, double b, double * ans);

int main(void)
{
	double x, y, z;

	cout << "Enter two numbers: ";
	while (cin >> x >> y)
	{
		if (hmean(x,y,&z))
			cout << "Harmonic mean of " << x << " and " << y
				<< " is " << z << "\n";
		else
			cout << "One value should not be the negative "
				<< "of the other - try again.\n";
		cout << "Enter next set of numbers : ";
	}
	cout << "Bye!\n";
	return 0;
}

Bool hmean(double a, double b, double * ans)
{
	if (a == -b)
	{
		*ans = DBL_MAX;
		return False;
	}
	else
	{
		*ans = 2.0 * a * b / (a + b);
		return True;
	}
}



//error3.cpp

#include <iostream.h>
#include <stdlib.h>
double hmean(double a, double b);

int main(void)
{
	double x, y, z;

	cout << "Enter two numbers: ";
	while (cin >> x >> y)
	{
		try {
			z = hmean(x,y);
		}	// end of try block
		catch (const char * s)	// start of exception handler
		{
			cout << s << "\n";
			cout << "Enter a new pair of numbers: ";
			continue;
		}	// end of handler
		cout << "Harmonic mean of " << x << " and " << y
			<< " is " << z << "\n";
		cout << "Enter next set of numbers : ";
	}
	cout << "Bye!\n";
	return 0;
}

double hmean(double a, double b)
{
	if (a == -b)
		throw "bad hmean() arguments: a = -b not allowed";
	return 2.0 * a * b / (a + b);
}



//error4.cpp

#include <iostream.h>
#include <stdlib.h>
#include <math.h> // for sqrt(); unix users may need -lm flag
double hmean(double a, double b) throw(const char *);
double gmean(double a, double b) throw(const char *);

int main(void)
{
	double x, y, z;

	cout << "Enter two numbers: ";
	try {
		while (cin >> x >> y)
		{
			z = hmean(x,y);
			cout << "Harmonic mean of " << x << " and " << y
				<< " is " << z << "\n";
			cout << "Geometric mean of " << x << " and " << y
				<< " is " << gmean(x,y) << "\n";
			cout << "Enter next set of numbers : ";
		}
	} // end of try block
	catch (const char * s)	// start of catch blcok
	{
		cout << s << "\n";
		cout << "Sorry, you don't get to play any more. ";
	}	// end of catch block
	cout << "Bye!\n";
	return 0;
}

double hmean(double a, double b) throw(const char *)
{
	if (a == -b)
		throw "bad hmean() arguments: a = -b not allowed";
	return 2.0 * a * b / (a + b);
}

double gmean(double a, double b) throw(const char *)
{
	if (a < 0 || b < 0)
		throw "bad gmean() arguments: negative values not allowed";
	return sqrt(a * b);
}


//error5.cpp

#include <iostream.h>
#include <stdlib.h>
double hmean(double a, double b);
void details(double a, double b);

int main(void)
{
	double x, y;

	cout << "Enter two numbers: ";
	try {
		while (cin >> x >> y)
			details(x,y);

	}
	catch (const char * s)
	{
		cout << s << "\n";
		cout << "Sorry, you can't play anymore. ";
	}
	cout << "Bye!\n";
	return 0;
}

double hmean(double a, double b)
{
	if (a == -b)
		throw "bad hmean() arguments: a = -b not allowed"
	return 2.0 * a * b / (a + b);
}

void details(double a, double b)
{
	cout << "Harmonic mean of " << a << " and " << b
		<< " is " << hmean(a,b) << "\n";
	cout << "Enter next set of numbers : ";
}



// arraydbe.h -- define array class with exceptions

#ifndef _ARRAYDBE_H_
#define _ARRAYDBE_H_
#include <iostream.h>

class ArrayDbE
{
private:
	unsigned int size;		// number of array elements
protected:
	double * arr;				// address of first element
public:
	class NoRoom		// exception class for insufficient memory 
	{
	public:
		int asked;		// bytes requested
		NoRoom(int i) : asked(i) {}
	};
	class BadIndex		// excepton class for indexing problems
	{
	public:
		int badindex;	// problematic index value
		BadIndex(int i) : badindex(i) {}
	};
	ArrayDbE();                          // default constructor
	// create an ArrayDbE of n elements, set each to val
	ArrayDbE(unsigned int n, double val = 0.0);
	// create an ArrayDbE of n elements, initialize to array pn
	ArrayDbE(const double * pn, unsigned int n);
	ArrayDbE(const ArrayDbE & a);         // copy constructor
	virtual ~ArrayDbE();                 // destructor
	unsigned int arsize() const;        // returns array size
// overloaded operators
		// array indexing, allowing assignment
	virtual double & operator[](int i);
		// array indexing (no =)
	virtual const double & operator[](int i) const;
	ArrayDbE & operator=(const ArrayDbE & a);
	friend ostream & operator<<(ostream & os, const ArrayDbE & a);
};

#endif


// arraydbe.cpp -- ArrayDbE class methods

#include <iostream.h>
#include "arraydbe.h"

// default constructor -- no arguments
ArrayDbE::ArrayDbE()
{
   arr = NULL;
   size = 0;
}

// constructs array of n elements, each set to val
ArrayDbE::ArrayDbE(unsigned int n, double val)
{
	arr = new double[n];
	if (arr == 0)
		throw NoRoom(n);
	size = n;
   for (int i = 0; i < size; i++)
       arr[i] = val;
}

// initialize ArrayDbE object to a non-class array
ArrayDbE::ArrayDbE(const double *pn, unsigned int n)
{
   arr = new double[n];
	if (arr == 0)
		throw NoRoom(n);
	size = n;
   for (int i = 0; i < size; i++)
       arr[i] = pn[i];
}

// initialize ArrayDbE object to another ArrayDbE object
ArrayDbE::ArrayDbE(const ArrayDbE & a)
{
   size = a.size;
	arr = new double[size];
	if (arr == 0)
		throw NoRoom(size);
	for (int i = 0; i < size; i++)
       arr[i] = a.arr[i];
}

ArrayDbE::~ArrayDbE()
{
   delete [] arr;
}

// return array size
unsigned int ArrayDbE::arsize() const
{
   return size;
}

// let user access elements by index (assignment allowed)
double & ArrayDbE::operator[](int i)
{
	// check index before continuing
	if (i < 0 || i >= size)
		throw BadIndex(i);
	return arr[i];
}

// let user access elements by index (assignment disallowed)
const double & ArrayDbE::operator[](int i) const
{
	// check index before continuing
	if (i < 0 || i >= size)
		throw BadIndex(i);
	return arr[i];
}

// define class assignment
ArrayDbE & ArrayDbE::operator=(const ArrayDbE & a)
{
   if (this == &a)      // if object assigned to self,
		return *this;	// don't change anything
   delete arr;
   size = a.size;
   arr = new double[size];
   for (int i = 0; i < size; i++)
       arr[i] = a.arr[i];
   return *this;
}

// quick output, 5 values to a line
ostream & operator<<(ostream & os, const ArrayDbE & a)
{
   for (int i = 0; i < a.size; i++)
   {
       os << a.arr[i] << " ";
       if (i % 5 == 4)
           os << "\n";
   }
   if (i % 5 != 0)
       os << "\n";
   return os;
}



// exceptar.cpp -- use the ArrayDbE class

// Compile with arraydbe.cpp
#include <iostream.h>
#include "arraydbe.h"

const int Players = 5;
int main(void)
{
	try {
		ArrayDbE Team(Players);
		cout << "Enter free-throw percentages for your 5 "
				"top players as a decimal fraction:\n";
		for (int player = 0; player < Players; player++)
		{
			 cout << "Player " << (player + 1) << ": % = ";
			 cin >> Team[player];
		}
		cout.precision(1);
		cout.setf(ios::showpoint);
		cout.setf(ios::fixed,ios::floatfield);
		cout << "Recapitulating, here are the percentages:\n";
		for (player = 0; player <= Players; player++)
			cout << "Player #" << (player + 1) << ": "
					<< 100.0 * Team[player] << "%\n";
	}	// end of try block
	catch (const ArrayDbE::NoRoom & nr) 	// 1st handler
	{
		cout << "ArrayDbE exception: "
				<< "Insufficient memory for " << nr.asked << "objects\n";
	}
	catch (const ArrayDbE::BadIndex & bi) 	// 2nd handler
	{
		cout << "ArrayDbE exception: "
				<< bi.badindex << " is a bad index value\n";
	}
	cout << "Bye!\n";
   return 0;
}



// limarre.h -- LimitArE class with exceptions


#ifndef _LIMARRE_H_
#define _LIMARRE_H_

#include "arraydbe.h"

class LimitArE : public ArrayDbE
{
protected:
   unsigned int low_bnd;      // new data member
   virtual void ok(int i) const;      // handle bounds checking
public:
class SonOfBad : public BadIndex
{
public:
	int l_lim;
	int u_lim;
	SonOfBad(int i, int l, int u) : BadIndex(i),
				l_lim(l), u_lim(u) {}
};
// constructors
	LimitArE() : ArrayDbE(), low_bnd(0) {} 
	LimitArE(unsigned int n, double val = 0.0)
				: ArrayDbE(n,val), low_bnd(0) {}
	LimitArE(unsigned int n, int lb, double val = 0.0)
				: ArrayDbE(n, val), low_bnd(lb) {}
	LimitArE(const double * pn, unsigned int n)
				: ArrayDbE(pn, n), low_bnd(0) {}
  	LimitArE(const ArrayDbE & a) : ArrayDbE(a), low_bnd(0) {}
// new methods
	void new_lb(int lb) {low_bnd = lb;}	// reset lower bound
	int lbound() {return low_bnd;}     // return lower bound
	int ubound() {return arsize() + low_bnd - 1;} // upper bound
// redefined operators
   double & operator[](int i);
   const double & operator[](int i) const;
};

endif




// limarre.cpp
#include "limarre.h"
#include <iostream.h>

// private method
   // lower bound for array index is now low_bnd, and 
   // upper bound is now low_bnd + size - 1
void LimitArE::ok(int i) const  // variable lower bound
{
	unsigned long size = arsize();
	if (i < low_bnd || i >= size + low_bnd)
		throw SonOfBad(i, low_bnd, low_bnd + size - 1);
}

// redefined operators
double & LimitArE::operator[](int i)
{
   ok(i);
   return arr[i - low_bnd];
}

const double & LimitArE::operator[](int i) const
{
   ok(i);
   return arr[i - low_bnd];
}



// excptinh.cpp -- use the ArrayDbE and LimitArE classes

// Compile with arraydbe.cpp
#include <iostream.h>
#include "arraydbe.h"
#include "limarre.h"

const int Years = 4;
const int FirstYear = 1990;
int main(void)
{
	int year;
	double total = 0;
	try {
		LimitArE income(Years, FirstYear);
		ArrayDbE busywork(Years);
		cout << "Enter your income for the last " << Years
				<< " years:\n";
		for (year = FirstYear; year < FirstYear + Years; year++)
		{
			 cout << "Year " << year << ": $";
			 cin >> income[year];
			 busywork[year - FirstYear] = 0.2 * income[year];
		}
		cout.precision(2);
		cout.setf(ios::showpoint);
		cout.setf(ios::fixed,ios::floatfield);
		cout << "Recapitulating, here are the figures:\n";
		for (year = FirstYear; year <= FirstYear + Years; year++)
		{
			cout << year << ": $" << income[year] << "\n";
			total += income[year];
		}
		cout << "busywork values: " << busywork;
	}	// end of try block
	catch (const ArrayDbE::NoRoom & nr) 	// 1st handler
	{
		cout << "ArrayDbE exception: "
				<< "Insufficient memory for " << nr.asked << "objects\n";
	}
	catch (const LimitArE::SonOfBad & bi) 	// 2nd handler
	{
		cout << "LimitArE exception: "
				<< bi.badindex << " is a bad index value\n";
		cout << "Index should be in the range " << bi.l_lim
				<< " to " << bi.u_lim << ".\n";
	}
	catch (const LimitArE::BadIndex & bi) 	// 3rd handler
	{
		cout << "ArrayDbE exception: "
				<< bi.badindex << " is a bad index value.\n";
	}
	cout << "Total income for " << (year - FirstYear)
			<< " years is $" << total << ".\n";
	cout << "Bye!\n";
	return 0;
}



RTTI



// rtti1.cpp -- use the RTTI dynamic_cast operator

#include <iostream.h>
#include <stdlib.h>
#include <time.h>
#include <typeinfo.h>

class Grand
{
private:
	int hold;
public:
	Grand(int h = 0) : hold(h) {}
	virtual void speak() { cout << "I am a grand class!\n";}
	virtual int value() { return hold; }
};

class Superb : public Grand
{
public:
	Superb(int h = 0) : Grand(h) {}
	void speak() {cout << "I am a superb class!!\n"; }
	virtual void say()
		{ cout << "I hold the superb value of " << value() << "!\n";}
};

class Magnificent : public Superb
{
private:
	char ch;
public:
	Magnificent(int h = 0, char c = 'A') : Superb(h), ch(c) {}
	void speak() {cout << "I am a magnificent class!!!\n";}
	void say() {cout << "I hold the character " << ch << " and the integer "
							<< value() << "!\n"; }
} ;

Grand * getone();
int main(void)
{
	srand(time(0));
	Grand * pg;
	Superb * ps;
	for (int i = 0; i < 5; i++)
	{
		pg = getone();
		pg->speak();
		if( ps = dynamic_cast(pg))
			ps->say();
	}
	return 0;
}

Grand * getone()	// generate one of three kinds of objects randomly
{
	Grand * p;
	switch( rand() % 3)
	{
		case 0:	p = new Grand(rand() % 100);
					break;
		case 1:	p = new Superb(rand() % 100);
					break;
		case 2:	p = new Magnificent(rand() % 100, 'A' + rand() % 26);
					break;
	}
	return p;
}



// rtti2.cpp  -- use dynamic_cast, typeid, and type_info

#include <iostream.h>
#include <stdlib.h>
#include <time.h>
#include <typeinfo.h>

class Grand
{
private:
	int hold;
public:
	Grand(int h = 0) : hold(h) {}
	virtual void speak() { cout << "I am a grand class!\n";}
	virtual int value() { return hold; }
};

class Superb : public Grand
{
public:
	Superb(int h = 0) : Grand(h) {}
	void speak() {cout << "I am a superb class!!\n"; }
	virtual void say()
		{ cout << "I hold the superb value of " << value() << "!\n";}
};

class Magnificent : public Superb
{
private:
	char ch;
public:
	Magnificent(int h = 0, char c = 'A') : Superb(h), ch(c) {}
	void speak() {cout << "I am a magnificent class!!!\n";}
	void say() {cout << "I hold the character " << ch << " and the integer "
							<< value() << "!\n"; }
} ;

Grand * getone();
int main(void)
{
	srand(time(0));
	Grand * pg;
	Superb * ps;
	for (int i = 0; i < 5; i++)
	{
		pg = getone();
		cout << "Now processing type " << typeid(*pg).name() << ".\n";
		pg->speak();
		if( ps = dynamic_cast(pg))
			ps->say();
		if (typeid(Magnificent) == typeid(*pg))
			cout << "Yes, you're really magnificent.\n";
}
	return 0;
}

Grand * getone()
{
	Grand * p;

	switch( rand() % 3)
	{
		case 0:	p = new Grand(rand() % 100);
					break;
		case 1:	p = new Superb(rand() % 100);
					break;
		case 2:	p = new Magnificent(rand() % 100, 'A' + rand() % 26);
					break;
	}
	return p;
}