Friends, Exceptions, and More |
|---|
// 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
// queuetp.h -- queue template with a nested class #include "booly.h" templateclass 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; }
//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;
}
// 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;
}