C++ primer plus(第六版)编程练习答案 第14章 C++中的代码重用

一、程序清单

studentc.h

// studentc.h -- defining a Student class using containment
#ifndef STUDENTC_H_
#define STUDENTC_H_

#include <iostream>
#include <string>   
#include <valarray>
class Student
{
private:
	typedef std::valarray<double> ArrayDb;
	std::string name;       // contained object
	ArrayDb scores;         // contained object
	// private method for scores output
	std::ostream & arr_out(std::ostream & os) const;
public:
	Student() : name("Null Student"), scores() {}
	explicit Student(const std::string & s)
		: name(s), scores() {}
	explicit Student(int n) : name("Nully"), scores(n) {}
	Student(const std::string & s, int n)
		: name(s), scores(n) {}
	Student(const std::string & s, const ArrayDb & a)
		: name(s), scores(a) {}
	Student(const char * str, const double * pd, int n)
		: name(str), scores(pd, n) {}
	~Student() {}
	double Average() const;
	const std::string & Name() const;
	double & operator[](int i);
	double operator[](int i) const;
	// friends
		// input
	friend std::istream & operator>>(std::istream & is,
		Student & stu);  // 1 word
	friend std::istream & getline(std::istream & is,
		Student & stu);     // 1 line
// output
	friend std::ostream & operator<<(std::ostream & os,
		const Student & stu);
};

#endif

studentc.cpp 

// studentc.cpp -- Student class using containment
#include "studentc.h"
using std::ostream;
using std::endl;
using std::istream;
using std::string;

//public methods
double Student::Average() const
{
	if (scores.size() > 0)
		return scores.sum() / scores.size();
	else
		return 0;
}

const string & Student::Name() const
{
	return name;
}

double & Student::operator[](int i)
{
	return scores[i];         // use valarray<double>::operator[]()
}

double Student::operator[](int i) const
{
	return scores[i];
}

// private method
ostream & Student::arr_out(ostream & os) const
{
	int i;
	int lim = scores.size();
	if (lim > 0)
	{
		for (i = 0; i < lim; i++)
		{
			os << scores[i] << " ";
			if (i % 5 == 4)
				os << endl;
		}
		if (i % 5 != 0)
			os << endl;
	}
	else
		os << " empty array ";
	return os;
}

// friends

// use string version of operator>>()
istream & operator>>(istream & is, Student & stu)
{
	is >> stu.name;
	return is;
}

// use string friend getline(ostream &, const string &)
istream & getline(istream & is, Student & stu)
{
	getline(is, stu.name);
	return is;
}

// use string version of operator<<()
ostream & operator<<(ostream & os, const Student & stu)
{
	os << "Scores for " << stu.name << ":\n";
	stu.arr_out(os);  // use private method for scores
	return os;
}

 use_stuc.cpp

// use_stuc.cpp -- using a composite class
// compile with studentc.cpp
#include <iostream>
#include "studentc.h"
using std::cin;
using std::cout;
using std::endl;

void set(Student & sa, int n);

const int pupils = 3;
const int quizzes = 5;

int main()
{
	Student ada[pupils] =
	{ Student(quizzes), Student(quizzes), Student(quizzes) };

	int i;
	for (i = 0; i < pupils; ++i)
		set(ada[i], quizzes);
	cout << "\nStudent List:\n";
	for (i = 0; i < pupils; ++i)
		cout << ada[i].Name() << endl;
	cout << "\nResults:";
	for (i = 0; i < pupils; ++i)
	{
		cout << endl << ada[i];
		cout << "average: " << ada[i].Average() << endl;
	}
	cout << "Done.\n";
	// cin.get();

	return 0;
}

void set(Student & sa, int n)
{
	cout << "Please enter the student's name: ";
	getline(cin, sa);
	cout << "Please enter " << n << " quiz scores:\n";
	for (int i = 0; i < n; i++)
		cin >> sa[i];
	while (cin.get() != '\n')
		continue;
}
// use_stuc.cpp -- using a composite class
// compile with studentc.cpp
#include <iostream>
#include "studentc.h"
using std::cin;
using std::cout;
using std::endl;

void set(Student & sa, int n);

const int pupils = 3;
const int quizzes = 5;

int main()
{
	Student ada[pupils] =
	{ Student(quizzes), Student(quizzes), Student(quizzes) };

	int i;
	for (i = 0; i < pupils; ++i)
		set(ada[i], quizzes);
	cout << "\nStudent List:\n";
	for (i = 0; i < pupils; ++i)
		cout << ada[i].Name() << endl;
	cout << "\nResults:";
	for (i = 0; i < pupils; ++i)
	{
		cout << endl << ada[i];
		cout << "average: " << ada[i].Average() << endl;
	}
	cout << "Done.\n";
	// cin.get();

	return 0;
}

void set(Student & sa, int n)
{
	cout << "Please enter the student's name: ";
	getline(cin, sa);
	cout << "Please enter " << n << " quiz scores:\n";
	for (int i = 0; i < n; i++)
		cin >> sa[i];
	while (cin.get() != '\n')
		continue;
}

执行结果: 

Please enter the student's name: Pat Roone
Please enter 5 quiz scores:
83 89 72 78 95
Please enter the student's name: Fleur O'Day
Please enter 5 quiz scores:
92 89 96 74 64

Student List:
Gil Bayts
Pat Roone
Fleur O'Day

Results:
Scores for Gil Bayts:
92 94 96 93 95
average: 94

Scores for Pat Roone:
83 89 72 78 95
average: 83.4

Scores for Fleur O'Day:
92 89 96 74 64
average: 83
Done.

 studenti.h 

// studenti.h -- defining a Student class using private inheritance
#ifndef STUDENTC_H_
#define STUDENTC_H_

#include <iostream>
#include <valarray>
#include <string>   
class Student : private std::string, private std::valarray<double>
{
private:
	typedef std::valarray<double> ArrayDb;
	// private method for scores output
	std::ostream & arr_out(std::ostream & os) const;
public:
	Student() : std::string("Null Student"), ArrayDb() {}
	explicit Student(const std::string & s)
		: std::string(s), ArrayDb() {}
	explicit Student(int n) : std::string("Nully"), ArrayDb(n) {}
	Student(const std::string & s, int n)
		: std::string(s), ArrayDb(n) {}
	Student(const std::string & s, const ArrayDb & a)
		: std::string(s), ArrayDb(a) {}
	Student(const char * str, const double * pd, int n)
		: std::string(str), ArrayDb(pd, n) {}
	~Student() {}
	double Average() const;
	double & operator[](int i);
	double operator[](int i) const;
	const std::string & Name() const;
	// friends
		// input
	friend std::istream & operator>>(std::istream & is,
		Student & stu);  // 1 word
	friend std::istream & getline(std::istream & is,
		Student & stu);     // 1 line
// output
	friend std::ostream & operator<<(std::ostream & os,
		const Student & stu);
};

#endif

studenti.cpp  

// studenti.cpp -- Student class using private inheritance
#include "studenti.h"
using std::ostream;
using std::endl;
using std::istream;
using std::string;

// public methods
double Student::Average() const
{
	if (ArrayDb::size() > 0)
		return ArrayDb::sum() / ArrayDb::size();
	else
		return 0;
}

const string & Student::Name() const
{
	return (const string &)*this;
}

double & Student::operator[](int i)
{
	return ArrayDb::operator[](i);         // use ArrayDb::operator[]()
}

double Student::operator[](int i) const
{
	return ArrayDb::operator[](i);
}

// private method
ostream & Student::arr_out(ostream & os) const
{
	int i;
	int lim = ArrayDb::size();
	if (lim > 0)
	{
		for (i = 0; i < lim; i++)
		{
			os << ArrayDb::operator[](i) << " ";
			if (i % 5 == 4)
				os << endl;
		}
		if (i % 5 != 0)
			os << endl;
	}
	else
		os << " empty array ";
	return os;
}

// friends
// use String version of operator>>()
istream & operator>>(istream & is, Student & stu)
{
	is >> (string &)stu;
	return is;
}

// use string friend getline(ostream &, const string &)
istream & getline(istream & is, Student & stu)
{
	getline(is, (string &)stu);
	return is;
}

// use string version of operator<<()
ostream & operator<<(ostream & os, const Student & stu)
{
	os << "Scores for " << (const string &)stu << ":\n";
	stu.arr_out(os);  // use private method for scores
	return os;
}

use_stui.cpp 

// use_stui.cpp -- using a class with private inheritance
// compile with studenti.cpp
#include <iostream>
#include "studenti.h"
using std::cin;
using std::cout;
using std::endl;

void set(Student & sa, int n);

const int pupils = 3;
const int quizzes = 5;

int main()
{
	Student ada[pupils] =
	{ Student(quizzes), Student(quizzes), Student(quizzes) };

	int i;
	for (i = 0; i < pupils; i++)
		set(ada[i], quizzes);
	cout << "\nStudent List:\n";
	for (i = 0; i < pupils; ++i)
		cout << ada[i].Name() << endl;
	cout << "\nResults:";
	for (i = 0; i < pupils; i++)
	{
		cout << endl << ada[i];
		cout << "average: " << ada[i].Average() << endl;
	}
	cout << "Done.\n";
	// cin.get();
	return 0;
}

void set(Student & sa, int n)
{
	cout << "Please enter the student's name: ";
	getline(cin, sa);
	cout << "Please enter " << n << " quiz scores:\n";
	for (int i = 0; i < n; i++)
		cin >> sa[i];
	while (cin.get() != '\n')
		continue;
}

执行结果:

Please enter the student's name: Pat Roone
Please enter 5 quiz scores:
83 89 72 78 95
Please enter the student's name: Fleur O'Day
Please enter 5 quiz scores:
92 89 96 74 64

Student List:
Gil Bayts
Pat Roone
Fleur O'Day

Results:
Scores for Gil Bayts:
92 94 96 93 95
average: 94

Scores for Pat Roone:
83 89 72 78 95
average: 83.4

Scores for Fleur O'Day:
92 89 96 74 64
average: 83
Done.

 ERROR解决:

“初始化”: 无法从“const char [6]”转换为“char *”    watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ZW_5rKZ5pyJ6IKl6bG8,size_20,color_FFFFFF,t_70,g_se,x_16

 将 worker0.cpp中的:

 char * Singer::pv[] = { "other", "alto", "contralto",
            "soprano", "bass", "baritone", "tenor" };

 (进行强制类型转换)修改为:

char * Singer::pv[] = {(char*)"other", (char*)"alto", (char*)"contralto",
            (char*)"soprano", (char*)"bass", (char*)"baritone", (char*)"tenor"};

worker0.h  

// worker0.h  -- working classes
#ifndef WORKER0_H_
#define WORKER0_H_

#include <string>

class Worker   // an abstract base class
{
private:
	std::string fullname;
	long id;
public:
	Worker() : fullname("no one"), id(0L) {}
	Worker(const std::string & s, long n)
		: fullname(s), id(n) {}
	virtual ~Worker() = 0;   // pure virtual destructor
	virtual void Set();
	virtual void Show() const;
};

class Waiter : public Worker
{
private:
	int panache;
public:
	Waiter() : Worker(), panache(0) {}
	Waiter(const std::string & s, long n, int p = 0)
		: Worker(s, n), panache(p) {}
	Waiter(const Worker & wk, int p = 0)
		: Worker(wk), panache(p) {}
	void Set();
	void Show() const;
};

class Singer : public Worker
{
protected:
	enum {
		other, alto, contralto, soprano,
		bass, baritone, tenor
	};
	enum { Vtypes = 7 };
private:
	static char *pv[Vtypes];    // string equivs of voice types
	int voice;
public:
	Singer() : Worker(), voice(other) {}
	Singer(const std::string & s, long n, int v = other)
		: Worker(s, n), voice(v) {}
	Singer(const Worker & wk, int v = other)
		: Worker(wk), voice(v) {}
	void Set();
	void Show() const;
};

#endif

 worker0.cpp

// worker0.cpp -- working class methods
#include "worker0.h"
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
// Worker methods

// must implement virtual destructor, even if pure
Worker::~Worker() {}

void Worker::Set()
{
	cout << "Enter worker's name: ";
	getline(cin, fullname);
	cout << "Enter worker's ID: ";
	cin >> id;
	while (cin.get() != '\n')
		continue;
}

void Worker::Show() const
{
	cout << "Name: " << fullname << "\n";
	cout << "Employee ID: " << id << "\n";
}

// Waiter methods
void Waiter::Set()
{
	Worker::Set();
	cout << "Enter waiter's panache rating: ";
	cin >> panache;
	while (cin.get() != '\n')
		continue;
}

void Waiter::Show() const
{
	cout << "Category: waiter\n";
	Worker::Show();
	cout << "Panache rating: " << panache << "\n";
}

// Singer methods

//char * Singer::pv[] = { "other", "alto", "contralto",
//			"soprano", "bass", "baritone", "tenor" };

char * Singer::pv[] = { (char*)"other", (char*)"alto", (char*)"contralto",
			(char*)"soprano", (char*)"bass", (char*)"baritone", (char*)"tenor" };

void Singer::Set()
{
	Worker::Set();
	cout << "Enter number for singer's vocal range:\n";
	int i;
	for (i = 0; i < Vtypes; i++)
	{
		cout << i << ": " << pv[i] << "   ";
		if (i % 4 == 3)
			cout << endl;
	}
	if (i % 4 != 0)
		cout << endl;
	while (cin >> voice && (voice < 0 || voice >= Vtypes))
		cout << "Please enter a value >= 0 and < " << Vtypes << endl;
	while (cin.get() != '\n')
		continue;
}

void Singer::Show() const
{
	cout << "Category: singer\n";
	Worker::Show();
	cout << "Vocal range: " << pv[voice] << endl;
}

worktest.cpp 

// worktest.cpp -- test worker class hierarchy
#include <iostream>
#include "worker0.h"
const int LIM = 4;
int main()
{
	Waiter bob("Bob Apple", 314L, 5);
	Singer bev("Beverly Hills", 522L, 3);
	Waiter w_temp;
	Singer s_temp;

	Worker * pw[LIM] = { &bob, &bev, &w_temp, &s_temp };

	int i;
	for (i = 2; i < LIM; i++)
		pw[i]->Set();
	for (i = 0; i < LIM; i++)
	{
		pw[i]->Show();
		std::cout << std::endl;
	}
	// std::cin.get();
	return 0;
}

执行结果:

Enter worker's name: Waldo Dropmaster
Enter worker's ID: 442
Enter waiter's panache rating: 3
Enter worker's name: Sylvie Sirenne
Enter worker's ID: 555
Enter number for singer's vocal range:
0: other   1: alto   2: contralto   3: soprano
4: bass   5: baritone   6: tenor
3
Category: waiter
Name: Bob Apple
Employee ID: 314
Panache rating: 5

Category: singer
Name: Beverly Hills
Employee ID: 522
Vocal range: soprano

Category: waiter
Name: Waldo Dropmaster
Employee ID: 442
Panache rating: 3

Category: singer
Name: Sylvie Sirenne
Employee ID: 555
Vocal range: soprano

workermi.h 

// workermi.h  -- working classes with MI
#ifndef WORKERMI_H_
#define WORKERMI_H_

#include <string>

class Worker   // an abstract base class
{
private:
	std::string fullname;
	long id;
protected:
	virtual void Data() const;
	virtual void Get();
public:
	Worker() : fullname("no one"), id(0L) {}
	Worker(const std::string & s, long n)
		: fullname(s), id(n) {}
	virtual ~Worker() = 0; // pure virtual function
	virtual void Set() = 0;
	virtual void Show() const = 0;
};

class Waiter : virtual public Worker
{
private:
	int panache;
protected:
	void Data() const;
	void Get();
public:
	Waiter() : Worker(), panache(0) {}
	Waiter(const std::string & s, long n, int p = 0)
		: Worker(s, n), panache(p) {}
	Waiter(const Worker & wk, int p = 0)
		: Worker(wk), panache(p) {}
	void Set();
	void Show() const;
};

class Singer : virtual public Worker
{
protected:
	enum {
		other, alto, contralto, soprano,
		bass, baritone, tenor
	};
	enum { Vtypes = 7 };
	void Data() const;
	void Get();
private:
	static char *pv[Vtypes];    // string equivs of voice types
	int voice;
public:
	Singer() : Worker(), voice(other) {}
	Singer(const std::string & s, long n, int v = other)
		: Worker(s, n), voice(v) {}
	Singer(const Worker & wk, int v = other)
		: Worker(wk), voice(v) {}
	void Set();
	void Show() const;
};

// multiple inheritance
class SingingWaiter : public Singer, public Waiter
{
protected:
	void Data() const;
	void Get();
public:
	SingingWaiter() {}
	SingingWaiter(const std::string & s, long n, int p = 0,
		int v = other)
		: Worker(s, n), Waiter(s, n, p), Singer(s, n, v) {}
	SingingWaiter(const Worker & wk, int p = 0, int v = other)
		: Worker(wk), Waiter(wk, p), Singer(wk, v) {}
	SingingWaiter(const Waiter & wt, int v = other)
		: Worker(wt), Waiter(wt), Singer(wt, v) {}
	SingingWaiter(const Singer & wt, int p = 0)
		: Worker(wt), Waiter(wt, p), Singer(wt) {}
	void Set();
	void Show() const;
};

#endif

workermi.cpp 

// workermi.cpp -- working class methods with MI
#include "workermi.h"
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
// Worker methods
Worker::~Worker() { }

// protected methods
void Worker::Data() const
{
	cout << "Name: " << fullname << endl;
	cout << "Employee ID: " << id << endl;
}

void Worker::Get()
{
	getline(cin, fullname);
	cout << "Enter worker's ID: ";
	cin >> id;
	while (cin.get() != '\n')
		continue;
}

// Waiter methods
void Waiter::Set()
{
	cout << "Enter waiter's name: ";
	Worker::Get();
	Get();
}

void Waiter::Show() const
{
	cout << "Category: waiter\n";
	Worker::Data();
	Data();
}

// protected methods
void Waiter::Data() const
{
	cout << "Panache rating: " << panache << endl;
}

void Waiter::Get()
{
	cout << "Enter waiter's panache rating: ";
	cin >> panache;
	while (cin.get() != '\n')
		continue;
}

// Singer methods

//char * Singer::pv[Singer::Vtypes] = { "other", "alto", "contralto",
//			"soprano", "bass", "baritone", "tenor" };

char * Singer::pv[] = { (char*)"other", (char*)"alto", (char*)"contralto",
			(char*)"soprano", (char*)"bass", (char*)"baritone", (char*)"tenor" };
void Singer::Set()
{
	cout << "Enter singer's name: ";
	Worker::Get();
	Get();
}

void Singer::Show() const
{
	cout << "Category: singer\n";
	Worker::Data();
	Data();
}

// protected methods
void Singer::Data() const
{
	cout << "Vocal range: " << pv[voice] << endl;
}

void Singer::Get()
{
	cout << "Enter number for singer's vocal range:\n";
	int i;
	for (i = 0; i < Vtypes; i++)
	{
		cout << i << ": " << pv[i] << "   ";
		if (i % 4 == 3)
			cout << endl;
	}
	if (i % 4 != 0)
		cout << '\n';
	while (cin >> voice && (voice < 0 || voice >= Vtypes))
		cout << "Please enter a value >= 0 and < " << Vtypes << endl;
	while (cin.get() != '\n')
		continue;
}

// SingingWaiter methods
void SingingWaiter::Data() const
{
	Singer::Data();
	Waiter::Data();
}

void SingingWaiter::Get()
{
	Waiter::Get();
	Singer::Get();
}

void SingingWaiter::Set()
{
	cout << "Enter singing waiter's name: ";
	Worker::Get();
	Get();
}

void SingingWaiter::Show() const
{
	cout << "Category: singing waiter\n";
	Worker::Data();
	Data();
}

workmi.cpp 

// workmi.cpp -- multiple inheritance
// compile with workermi.cpp
#include <iostream>
#include <cstring>
#include "workermi.h"
const int SIZE = 5;

int main()
{
	using std::cin;
	using std::cout;
	using std::endl;
	using std::strchr;

	Worker * lolas[SIZE];

	int ct;
	for (ct = 0; ct < SIZE; ct++)
	{
		char choice;
		cout << "Enter the employee category:\n"
			<< "w: waiter  s: singer  "
			<< "t: singing waiter  q: quit\n";
		cin >> choice;
		while (strchr("wstq", choice) == NULL)
		{
			cout << "Please enter a w, s, t, or q: ";
			cin >> choice;
		}
		if (choice == 'q')
			break;
		switch (choice)
		{
		case 'w':   lolas[ct] = new Waiter;
			break;
		case 's':   lolas[ct] = new Singer;
			break;
		case 't':   lolas[ct] = new SingingWaiter;
			break;
		}
		cin.get();
		lolas[ct]->Set();
	}

	cout << "\nHere is your staff:\n";
	int i;
	for (i = 0; i < ct; i++)
	{
		cout << endl;
		lolas[i]->Show();
	}
	for (i = 0; i < ct; i++)
		delete lolas[i];
	cout << "Bye.\n";
	// cin.get();
	// cin.get();
	return 0;
}

执行结果:

Enter the employee category:
w: waiter  s: singer  t: singing waiter  q: quit
w
Enter waiter's name: Wally Slipshod
Enter worker's ID: 1040
Enter waiter's panache rating: 4
Enter the employee category:
w: waiter  s: singer  t: singing waiter  q: quit
s
Enter singer's name: Sinclair Parma
Enter worker's ID: 1044
Enter number for singer's vocal range:
0: other   1: alto   2: contralto   3: soprano
4: bass   5: baritone   6: tenor
5
Enter the employee category:
w: waiter  s: singer  t: singing waiter  q: quit
t
Enter singing waiter's name: Natasha Gargalova
Enter worker's ID: 1021
Enter waiter's panache rating: 6
Enter number for singer's vocal range:
0: other   1: alto   2: contralto   3: soprano
4: bass   5: baritone   6: tenor
3
Enter the employee category:
w: waiter  s: singer  t: singing waiter  q: quit
q

Here is your staff:

Category: waiter
Name: Wally Slipshod
Employee ID: 1040
Panache rating: 4

Category: singer
Name: Sinclair Parma
Employee ID: 1044
Vocal range: baritone

Category: singing waiter
Name: Natasha Gargalova
Employee ID: 1021
Vocal range: soprano
Panache rating: 6
Bye.

stacktp.h 

// stacktp.h -- a stack template
#ifndef STACKTP_H_
#define STACKTP_H_
template <class Type>
class Stack
{
private:
	enum { MAX = 10 };    // constant specific to class
	Type items[MAX];    // holds stack items
	int top;            // index for top stack item
public:
	Stack();
	bool isempty();
	bool isfull();
	bool push(const Type & item); // add item to stack
	bool pop(Type & item);        // pop top into item
};

template <class Type>
Stack<Type>::Stack()
{
	top = 0;
}

template <class Type>
bool Stack<Type>::isempty()
{
	return top == 0;
}

template <class Type>
bool Stack<Type>::isfull()
{
	return top == MAX;
}

template <class Type>
bool Stack<Type>::push(const Type & item)
{
	if (top < MAX)
	{
		items[top++] = item;
		return true;
	}
	else
		return false;
}

template <class Type>
bool Stack<Type>::pop(Type & item)
{
	if (top > 0)
	{
		item = items[--top];
		return true;
	}
	else
		return false;
}

#endif

stacktem.cpp 

// stacktem.cpp -- testing the template stack class
#include <iostream>
#include <string>
#include <cctype>
#include "stacktp.h"
using std::cin;
using std::cout;

int main()
{
	Stack<std::string> st;   // create an empty stack
	char ch;
	std::string po;
	cout << "Please enter A to add a purchase order,\n"
		<< "P to process a PO, or Q to quit.\n";
	while (cin >> ch && std::toupper(ch) != 'Q')
	{
		while (cin.get() != '\n')
			continue;
		if (!std::isalpha(ch))
		{
			cout << '\a';
			continue;
		}
		switch (ch)
		{
		case 'A':
		case 'a': cout << "Enter a PO number to add: ";
			cin >> po;
			if (st.isfull())
				cout << "stack already full\n";
			else
				st.push(po);
			break;
		case 'P':
		case 'p': if (st.isempty())
			cout << "stack already empty\n";
				  else {
			st.pop(po);
			cout << "PO #" << po << " popped\n";
			break;
		}
		}
		cout << "Please enter A to add a purchase order,\n"
			<< "P to process a PO, or Q to quit.\n";
	}
	cout << "Bye\n";
	// cin.get();
	// cin.get();
	return 0;
}

执行结果:

Please enter A to add a purchase order,
P to process a PO, or Q to quit.
A
Enter a PO number to add: red911porsche
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
A
Enter a PO number to add: blueR8audi
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
A
Enter a PO number to add: silver747boeing
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
P
PO #silver747boeing popped
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
P
PO #blueR8audi popped
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
P
PO #red911porsche popped
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
P
stack already empty
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
Q
Bye

stcktp1.h 

// stcktp1.h -- modified Stack template
#ifndef STCKTP1_H_
#define STCKTP1_H_

template <class Type>
class Stack
{
private:
    enum {SIZE = 10};    // default size
    int stacksize;
    Type * items;       // holds stack items
    int top;            // index for top stack item
public:
    explicit Stack(int ss = SIZE);
    Stack(const Stack & st);
    ~Stack() { delete [] items; }
    bool isempty() { return top == 0; }
    bool isfull() { return top == stacksize; }
    bool push(const Type & item);   // add item to stack
    bool pop(Type & item);          // pop top into item
    Stack & operator=(const Stack & st);
};

template <class Type>
Stack<Type>::Stack(int ss) : stacksize(ss), top(0)
{
    items = new Type [stacksize];
}

template <class Type>
Stack<Type>::Stack(const Stack & st)
{
    stacksize = st.stacksize;
    top = st.top;
    items = new Type [stacksize];
    for (int i = 0; i < top; i++)
        items[i] = st.items[i];
}

template <class Type>
bool Stack<Type>::push(const Type & item)
{
    if (top < stacksize)
    {
        items[top++] = item;
        return true;
    }
    else
        return false;
}

template <class Type>
bool Stack<Type>::pop(Type & item)
{
    if (top > 0)
    {
        item = items[--top];
        return true;
    }
    else
        return false;
}

template <class Type>
Stack<Type> & Stack<Type>::operator=(const Stack<Type> & st)
{
    if (this == &st)
        return *this;
    delete [] items;
    stacksize = st.stacksize;
    top = st.top;
    items = new Type [stacksize];
    for (int i = 0; i < top; i++)
        items[i] = st.items[i];
    return *this; 
}

#endif

stkoptr1.cpp  

// stkoptr1.cpp -- testing stack of pointers
#include <iostream>
#include <cstdlib>     // for rand(), srand()
#include <ctime>       // for time()
#include "stcktp1.h"
const int Num = 10;
int main()
{
    std::srand(std::time(0)); // randomize rand()
    std::cout << "Please enter stack size: ";
    int stacksize;
    std::cin >> stacksize;
// create an empty stack with stacksize slots
    Stack<const char *> st(stacksize); 

// in basket
    const char * in[Num] = {
            " 1: Hank Gilgamesh", " 2: Kiki Ishtar",
            " 3: Betty Rocker", " 4: Ian Flagranti",
            " 5: Wolfgang Kibble", " 6: Portia Koop",
            " 7: Joy Almondo", " 8: Xaverie Paprika",
            " 9: Juan Moore", "10: Misha Mache"
            };
 // out basket
    const char * out[Num];

    int processed = 0;
    int nextin = 0;
    while (processed < Num)
    {
        if (st.isempty())
            st.push(in[nextin++]);
        else if (st.isfull())
            st.pop(out[processed++]);
        else if (std::rand() % 2  && nextin < Num)   // 50-50 chance
            st.push(in[nextin++]);
        else
            st.pop(out[processed++]);
    }
    for (int i = 0; i < Num; i++)
        std::cout << out[i] << std::endl;

    std::cout << "Bye\n";
    // std::cin.get();
    // std::cin.get();
	return 0; 
}

执行结果:

Please enter stack size: 5
 1: Hank Gilgamesh
 4: Ian Flagranti
 6: Portia Koop
 8: Xaverie Paprika
 9: Juan Moore
10: Misha Mache
 7: Joy Almondo
 5: Wolfgang Kibble
 3: Betty Rocker
 2: Kiki Ishtar
Bye
Please enter stack size: 5
 2: Kiki Ishtar
 1: Hank Gilgamesh
 3: Betty Rocker
 4: Ian Flagranti
 6: Portia Koop
 9: Juan Moore
10: Misha Mache
 8: Xaverie Paprika
 7: Joy Almondo
 5: Wolfgang Kibble
Bye

arraytp.h 

//arraytp.h  -- Array Template
#ifndef ARRAYTP_H_
#define ARRAYTP_H_

#include <iostream>
#include <cstdlib>

template <class T, int n>
class ArrayTP
{
private:
	T ar[n];
public:
	ArrayTP() {};
	explicit ArrayTP(const T & v);
	virtual T & operator[](int i);
	virtual T operator[](int i) const;
};

template <class T, int n>
ArrayTP<T, n>::ArrayTP(const T & v)
{
	for (int i = 0; i < n; i++)
		ar[i] = v;
}

template <class T, int n>
T & ArrayTP<T, n>::operator[](int i)
{
	if (i < 0 || i >= n)
	{
		std::cerr << "Error in array limits: " << i
			<< " is out of range\n";
		std::exit(EXIT_FAILURE);
	}
	return ar[i];
}

template <class T, int n>
T ArrayTP<T, n>::operator[](int i) const
{
	if (i < 0 || i >= n)
	{
		std::cerr << "Error in array limits: " << i
			<< " is out of range\n";
		std::exit(EXIT_FAILURE);
	}
	return ar[i];
}

#endif

twod.cpp 

// twod.cpp -- making a 2-d array
#include <iostream>
#include "arraytp.h"
int main(void)
{
	using std::cout;
	using std::endl;
	ArrayTP<int, 10> sums;
	ArrayTP<double, 10> aves;
	ArrayTP< ArrayTP<int, 5>, 10> twodee;


	int i, j;

	for (i = 0; i < 10; i++)
	{
		sums[i] = 0;
		for (j = 0; j < 5; j++)
		{
			twodee[i][j] = (i + 1) * (j + 1);
			sums[i] += twodee[i][j];
		}
		aves[i] = (double)sums[i] / 5;
	}
	for (i = 0; i < 10; i++)
	{
		for (j = 0; j < 5; j++)
		{
			cout.width(2);
			cout << twodee[i][j] << ' ';
		}
		cout << ": sum = ";
		cout.width(3);
		cout << sums[i] << ", average = " << aves[i] << endl;
	}

	cout << "Done.\n";
	// std::cin.get();
	return 0;
}

执行结果:

 1  2  3  4  5 : sum =  15, average = 3
 2  4  6  8 10 : sum =  30, average = 6
 3  6  9 12 15 : sum =  45, average = 9
 4  8 12 16 20 : sum =  60, average = 12
 5 10 15 20 25 : sum =  75, average = 15
 6 12 18 24 30 : sum =  90, average = 18
 7 14 21 28 35 : sum = 105, average = 21
 8 16 24 32 40 : sum = 120, average = 24
 9 18 27 36 45 : sum = 135, average = 27
10 20 30 40 50 : sum = 150, average = 30
Done.

pairs.cpp  

// pairs.cpp -- defining and using a Pair template
#include <iostream>
#include <string>
template <class T1, class T2>
class Pair
{
private:
	T1 a;
	T2 b;
public:
	T1 & first();
	T2 & second();
	T1 first() const { return a; }
	T2 second() const { return b; }
	Pair(const T1 & aval, const T2 & bval) : a(aval), b(bval) { }
	Pair() {}
};

template<class T1, class T2>
T1 & Pair<T1, T2>::first()
{
	return a;
}
template<class T1, class T2>
T2 & Pair<T1, T2>::second()
{
	return b;
}

int main()
{
	using std::cout;
	using std::endl;
	using std::string;
	Pair<string, int> ratings[4] =
	{
		Pair<string, int>("The Purpled Duck", 5),
		Pair<string, int>("Jaquie's Frisco Al Fresco", 4),
		Pair<string, int>("Cafe Souffle", 5),
		Pair<string, int>("Bertie's Eats", 3)
	};

	int joints = sizeof(ratings) / sizeof(Pair<string, int>);
	cout << joints << endl;//输出joints的值
	cout << "Rating:\t Eatery\n";
	for (int i = 0; i < joints; i++)
		cout << ratings[i].second() << ":\t "
		<< ratings[i].first() << endl;
	cout << "Oops! Revised rating:\n";
	ratings[3].first() = "Bertie's Fab Eats";
	ratings[3].second() = 6;
	cout << ratings[3].second() << ":\t "
		<< ratings[3].first() << endl;
	// std::cin.get();
	return 0;
}

执行结果:

4
Rating:  Eatery
5:       The Purpled Duck
4:       Jaquie's Frisco Al Fresco
5:       Cafe Souffle
3:       Bertie's Eats
Oops! Revised rating:
6:       Bertie's Fab Eats

tempmemb.cpp  

// tempmemb.cpp -- template members
#include <iostream>
using std::cout;
using std::endl;

template <typename T>
class beta
{
private:
	template <typename V>  // nested template class member
	class hold
	{
	private:
		V val;
	public:
		hold(V v = 0) : val(v) {}
		void show() const { cout << val << endl; }
		V Value() const { return val; }
	};
	hold<T> q;             // template object
	hold<int> n;           // template object
public:
	beta(T t, int i) : q(t), n(i) {}
	template<typename U>   // template method
	U blab(U u, T t) { return (n.Value() + q.Value()) * u / t; }
	void Show() const { q.show(); n.show(); }
};

int main()
{
	beta<double> guy(3.5, 3);
	cout << "T was set to double\n";
	guy.Show();
	cout << "V was set to T, which is double, then V was set to int\n";
	cout << guy.blab(10, 2.3) << endl;
	cout << "U was set to int\n";
	cout << guy.blab(10.0, 2.3) << endl;
	cout << "U was set to double\n";
	cout << "Done\n";
	// std::cin.get();
	return 0;
}

执行结果: 

T was set to double
3.5
3
V was set to T, which is double, then V was set to int
28
U was set to int
28.2609
U was set to double
Done

stacktp.h 

// stacktp.h -- a stack template
#ifndef STACKTP_H_
#define STACKTP_H_
template <class Type>
class Stack
{
private:
	enum { MAX = 10 };    // constant specific to class
	Type items[MAX];    // holds stack items
	int top;            // index for top stack item
public:
	Stack();
	bool isempty();
	bool isfull();
	bool push(const Type & item); // add item to stack
	bool pop(Type & item);        // pop top into item
};

template <class Type>
Stack<Type>::Stack()
{
	top = 0;
}

template <class Type>
bool Stack<Type>::isempty()
{
	return top == 0;
}

template <class Type>
bool Stack<Type>::isfull()
{
	return top == MAX;
}

template <class Type>
bool Stack<Type>::push(const Type & item)
{
	if (top < MAX)
	{
		items[top++] = item;
		return true;
	}
	else
		return false;
}

template <class Type>
bool Stack<Type>::pop(Type & item)
{
	if (top > 0)
	{
		item = items[--top];
		return true;
	}
	else
		return false;
}

#endif

tempparm.cpp 

// tempparm.cpp ?templates as parameters
#include <iostream>
#include "stacktp.h"

template <template <typename T> class Thing>
class Crab
{
private:
	Thing<int> s1;
	Thing<double> s2;
public:
	Crab() {};
	// assumes the thing class has push() and pop() members
	bool push(int a, double x) { return s1.push(a) && s2.push(x); }
	bool pop(int & a, double & x) { return s1.pop(a) && s2.pop(x); }
};

int main()
{
	using std::cout;
	using std::cin;
	using std::endl;
	Crab<Stack> nebula;
	// Stack must match template <typename T> class thing   
	int ni;
	double nb;
	cout << "Enter int double pairs, such as 4 3.5 (0 0 to end):\n";
	while (cin >> ni >> nb && ni > 0 && nb > 0)
	{
		if (!nebula.push(ni, nb))
			break;
	}

	while (nebula.pop(ni, nb))
		cout << ni << ", " << nb << endl;
	cout << "Done.\n";
	// cin.get();
	// cin.get();
	return 0;
}

执行结果:

Enter int double pairs, such as 4 3.5 (0 0 to end):
50 22.48
25 33.87
60 19.12
0 0
60, 19.12
25, 33.87
50, 22.48
Done.

frnd2tmp.cpp 

// frnd2tmp.cpp -- template class with non-template friends
#include <iostream>
using std::cout;
using std::endl;

template <typename T>
class HasFriend
{
private:
	T item;
	static int ct;
public:
	HasFriend(const T & i) : item(i) { ct++; }
	~HasFriend() { ct--; }
	friend void counts();
	friend void reports(HasFriend<T> &); // template parameter
};

// each specialization has its own static data member
template <typename T>
int HasFriend<T>::ct = 0;

// non-template friend to all HasFriend<T> classes
void counts()
{
	cout << "int count: " << HasFriend<int>::ct << "; ";
	cout << "double count: " << HasFriend<double>::ct << endl;
}

// non-template friend to the HasFriend<int> class
void reports(HasFriend<int> & hf)
{
	cout << "HasFriend<int>: " << hf.item << endl;
}

// non-template friend to the HasFriend<double> class
void reports(HasFriend<double> & hf)
{
	cout << "HasFriend<double>: " << hf.item << endl;
}

int main()
{
	cout << "No objects declared: ";
	counts();
	HasFriend<int> hfi1(10);
	cout << "After hfi1 declared: ";
	counts();
	HasFriend<int> hfi2(20);
	cout << "After hfi2 declared: ";
	counts();
	HasFriend<double> hfdb(10.5);
	cout << "After hfdb declared: ";
	counts();
	reports(hfi1);
	reports(hfi2);
	reports(hfdb);
	// std::cin.get();
	return 0;
}

执行结果:

No objects declared: int count: 0; double count: 0
After hfi1 declared: int count: 1; double count: 0
After hfi2 declared: int count: 2; double count: 0
After hfdb declared: int count: 2; double count: 1
HasFriend<int>: 10
HasFriend<int>: 20
HasFriend<double>: 10.5

 tmp2tmp.cpp

// tmp2tmp.cpp -- template friends to a template class
#include <iostream>
using std::cout;
using std::endl;

// template prototypes
template <typename T> void counts();
template <typename T> void report(T &);

// template class
template <typename TT>
class HasFriendT
{
private:
	TT item;
	static int ct;
public:
	HasFriendT(const TT & i) : item(i) { ct++; }
	~HasFriendT() { ct--; }
	friend void counts<TT>();
	friend void report<>(HasFriendT<TT> &);
};

template <typename T>
int HasFriendT<T>::ct = 0;

// template friend functions definitions
template <typename T>
void counts()
{
	cout << "template size: " << sizeof(HasFriendT<T>) << "; ";
	cout << "template counts(): " << HasFriendT<T>::ct << endl;
}

template <typename T>
void report(T & hf)
{
	cout << hf.item << endl;
}

int main()
{
	counts<int>();
	HasFriendT<int> hfi1(10);
	HasFriendT<int> hfi2(20);
	HasFriendT<double> hfdb(10.5);
	report(hfi1);  // generate report(HasFriendT<int> &)
	report(hfi2);  // generate report(HasFriendT<int> &)
	report(hfdb);  // generate report(HasFriendT<double> &)
	cout << "counts<int>() output:\n";
	counts<int>();
	cout << "counts<double>() output:\n";
	counts<double>();
	// std::cin.get();
	return 0;
}

执行结果:

template size: 4; template counts(): 0
10
20
10.5
counts<int>() output:
template size: 4; template counts(): 2
counts<double>() output:
template size: 8; template counts(): 1

manyfrnd.cpp 

// manyfrnd.cpp -- unbound template friend to a template class
#include <iostream>
using std::cout;
using std::endl;

template <typename T>
class ManyFriend
{
private:
	T item;
public:
	ManyFriend(const T & i) : item(i) {}
	template <typename C, typename D> friend void show2(C &, D &);
};

template <typename C, typename D> void show2(C & c, D & d)
{
	cout << c.item << ", " << d.item << endl;
}

int main()
{
	ManyFriend<int> hfi1(10);
	ManyFriend<int> hfi2(20);
	ManyFriend<double> hfdb(10.5);
	cout << "hfi1, hfi2: ";
	show2(hfi1, hfi2);
	cout << "hfdb, hfi2: ";
	show2(hfdb, hfi2);
	// std::cin.get();
	return 0;
}

执行结果:

hfi1, hfi2: 10, 20
hfdb, hfi2: 10.5, 20

 

二、复习题

1. 以A栏的类为基类时,B栏的类采用公有派生还是私有派生更合适

AB
class Bear
class Kitchen
class Person
class Person
class Person, class Automobile
class PolarBear
class Home
class Programmer
class HorseAndJockey
class Driver
AB公有派生还是私有派生合适
class Bearclass PolarBear公有派生,因为北极熊也是一种熊,is-a的关系
class Kitchenclass Home私有派生,因为家中有厨房,has-a的关系
class Personclass Programmer公有派生,因为程序员也是人,is-a的关系
class Personclass HorseAndJockey私有派生,因为马和驯马师的组合包人,has-a的关系
class Person, class Automobileclass Driver人是公有的,人与司机是is-a关系;车是私有的,车与司机是has-a的关系

2. 假设有下面的定义:

class Frabjous {
    private:
    char fab[20];
    public:
    Frabjous(const char * s = "C++") : fab(s) { }
    virtual void tell() { cout << fab; }
};
class Gloam {
    private:
    int glip;
    Frabjous fb;
    public:
    Gloam(int g = 0, const char * s = "C++");
    Gloam(int g, const Frabjous & f);
    void tell();
};

假设Gloam版本的tell()应显示glipfb的值,请为这3个Gloam方法提供定义。

Gloam::Gloam(int g, const char* s) : glip(g), fb(s){}
Gloam::Gloam(int g, const Frabjous &f) : glip(g), fb(f){} //使用Frabjous的默认复制构造函数
void Golam::tell()
{
    fb.tell();
    cout << glip <<endl;
}

3. 假设有下面的定义:

class Frabjous {
    private:
    char fab[20];
    public:
    Frabjous(const char * s = "C++") : fab(s) { }
    virtual void tell() { cout << fab; }
};
class Gloam : private Frabjous{
    private:
    int glip;
    public:
    Gloam(int g = 0, const char * s = "C++");
    Gloam(int g, const Frabjous & f);
    void tell();
};

假设Gloam版本的tell()应显示glipfab的值,请为这3个Gloam方法提供定义。

Gloam::Gloam(int g, const char* s) : glip(g), Frabjous(s){}
Gloam::Gloam(int g, const Frabjous &f) : glip(g), Frabjous(f){} //使用Frabjous的默认复制构造函数
void Golam::tell()
{
    Frabjous::tell();
    cout << glip <<endl;
}

4. 假设有下面的定义,它是基于程序清单14.13中的Stack模板和程序清单14.10中的Woker类的:

Stack<Worker *> sw;

请写出将生成的类声明。只实现类声明,不实现非内联类方法。

class Stack<Worker *>
{
  private:
    enum {MAX = 10}; // constant specific to class
    Worker * items[MAX]; // holds stack items
    int top; // index for top stack item

  public:
    Stack();
    Boolean isempty();
    Boolean isfull();
    Boolean push(const Worker * & item); // add item to stack
    Boolean pop(Worker * & item); // pop top into item
}

5. 使用本章中的模板定义对下面的内容进行定义:

  • string对象数组;

  • double数组栈;

  • 指向`Worker`对象的指针的栈数组。

程序清单14.18生成了多少个模板类定义?

ArrayTP<string> str_arr;//string对象数组
StackTP<ArrayTP<double> db_arr_stack;//double数组栈
ArrayTP<StackTP<Worker *>> wkptr_ stack_arr;//指向Worker对象的指针的栈数组   

程序清单14.18生成4个模板:ArrayTP<int, 10>ArrayTP<double,10>、ArrayTP<int, 5>Array<ArrayTP <int, 5>, 10>

6. 指出虚基类与非虚基类之间的区别。

如果两条继承路线有相同的祖先,非虚基类会导致最终的派生类中包含祖先成员的两份拷贝,虚基类可以解决这种问题。

三、编程练习

1.Wine类有一个string类对象成员(参见第4章)和一个Pair对象(参见本章);其中前者用于存储葡萄酒的名称,而后者有2个valarray<int>对象(参见本章),这两个valarray<int>对象分别保存了葡萄酒的酿造年份和该年生产的瓶数。例如,Pair的第1个valarray<int>对象可能为1988、1992和1996年,第2个valarray<int>对象可能为24、48和144瓶。Wine最好有1个int成员用于存储年数。另外,一些typedef可能有助于简化编程工作:

typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;

这样,PairArray表示Pair<std::valarray<int>,std::valarray<int>>。使用包含来实现Wine类,并用一个简单的程序对其进行测试。Wine类应该有一个默认构造函数以及如下构造函数:

// initialize label to l, number of years to y,
// vintage years to yr[], bottles to bot[]
Wine(const char * l, int y, const int yr[], const int bot[]);
// initialize label to l, number of years to y,
// create array objects of length y
Wine(const char * l, int y);

Wine类应该有一个GetBottles()方法,它根据Wine对象能够存储几种年份(y),提示用户输入年份和瓶数。方法Label()返回一个指向葡萄酒名称的引用。sum()方法返回Pair对象中第二个valarray<int>对象中的瓶数总和。测试程序应提示用户输入葡萄酒名称、元素个数以及每个元素存储的年份和瓶数等信息。程序将使用这些数据来构造一个Wine对象,然后显示对象中保存的信息。

下面是一个简单的测试程序:

// pe14-1.cpp -- using Wine class with containment
#include <iostream>
#include "winec.h"
int main ( void )
{
    using std::cin;
    using std::cout;
    using std::endl;
    cout << "Enter name of wine: ";
    char lab[50];
    cin.getline(lab, 50);
    cout << "Enter number of years: ";
    int yrs;
    cin >> yrs;
    Wine holding(lab, yrs); // store label, years, give arrays yrs elements
    holding.GetBottles(); // solicit input for year, bottle count
    holding.Show(); // display object contents
    const int YRS = 3;
    int y[YRS] = {1993, 1995, 1998};
    int b[YRS] = { 48, 60, 72};
    // create new object, initialize using data in arrays y and b
    Wine more("Gushing Grape Red",YRS, y, b);
    more.Show();
    cout << "Total bottles for " << more.Label() // use Label() method
        << ": " << more.sum() << endl; // use sum() method
    cout << "Bye\n";
    return 0;
}

下面是该程序的运行情况

Enter name of wine: Gully Wash
Enter number of years: 4
Enter Gully Wash data for 4 year(s):
Enter year: 1988
Enter bottles for that year: 42
Enter year: 1994
Enter bottles for that year: 58
Enter year: 1998
Enter bottles for that year: 122
Enter year: 2001
Enter bottles for that year: 144
Wine: Gully Wash
Year Bottles
1988 42
1994 58
1998 122
2001 144
Wine: Gushing Grape Red
Year Bottles
1993 48
1995 60
1998 72
Total bottles for Gushing Grape Red: 180
Bye

pair.cpp:

#ifndef PAIR_H_
#define PAIR_H_

template <typename T1, typename T2>
class Pair {
    private:
    T1 t1;
    T2 t2;

    public:
    Pair(const T1& t1, const T2& t2) : t1(t1), t2(t2) {}
    Pair(const Pair<T1, T2>& p);
    T1& first();
    T2& second();
    T1 first() const { return t1; }
    T2 second() const { return t2; }
};

template <typename T1, typename T2>
Pair<T1, T2>::Pair(const Pair<T1, T2>& p) {
    t1 = p.t1;
    t2 = p.t2;
}

template <typename T1, typename T2>
T1& Pair<T1, T2>::first() {
    return t1;
}

template <typename T1, typename T2>
T2& Pair<T1, T2>::second() {
    return t2;
}

#endif  // PAIR_H_

winec.h:

#ifndef WINEC_H_
#define WINEC_H_

#include <iostream>
#include <string>
#include <valarray>

#include "pair.h"

class Wine {
    private:
    typedef std::valarray<int> ArrayInt;
    typedef Pair<ArrayInt, ArrayInt> PairArray;
    std::string label;
    PairArray data;
    int years_num;

    public:
    Wine(const char* l, int y, const int yr[], const int bot[]);
    Wine(const char* l, int y);
    void GetBottles();
    const std::string& Label() const { return label; }
    int sum() const;
    void Show() const;
};

#endif  // WINEC_H_

winec.cpp:

#include "winec.h"

Wine::Wine(const char* l, int y, const int yr[], const int bot[])
    : label(l), years_num(y), data(ArrayInt(yr, y), ArrayInt(bot, y)) {}

Wine::Wine(const char* l, int y)
    : label(l), years_num(y), data(ArrayInt(y), ArrayInt(y)) {}

void Wine::GetBottles() {
    int yn = 0;
    int b = 0;

    std::cout << "Enter " << label << " data for " << years_num << " year(s)"
        << std::endl;

    for (int i = 0; i < years_num; ++i) {
        std::cout << "Enter year: ";
        std::cin >> yn;
        data.first()[i] = yn;
        std::cout << "Enter bottles for that year: ";
        std::cin >> b;
        data.second()[i] = b;
    }
}

int Wine::sum() const { return data.second().sum(); }

void Wine::Show() const {
    std::cout << "Wine: " << label << std::endl;
    std::cout << "Year  "
        << "  Bottles" << std::endl;
    for (int i = 0; i < years_num; ++i) {
        std::cout << data.second()[i] << "    " << data.first()[i] << std::endl;
    }
}

2. 采用私有继承而不是包含来完成编程练习1。同样,一些typedef可能会有所帮助,另外,您可能还需要考虑诸如下面这样的语句的含义:

PairArray::operator=(PairArray(ArrayInt(),ArrayInt()));
cout << (const string &)(*this);

您设计的类应该可以使用编程练习1中的测试程序进行测试。

pair.cpp:

#ifndef PAIR_H_
#define PAIR_H_

template <typename T1, typename T2>
class Pair {
    private:
    T1 t1;
    T2 t2;

    public:
    Pair(const T1& t1, const T2& t2) : t1(t1), t2(t2) {}
    Pair(const Pair<T1, T2>& p);
    T1& first();
    T2& second();
    T1 first() const { return t1; }
    T2 second() const { return t2; }
};

template <typename T1, typename T2>
Pair<T1, T2>::Pair(const Pair<T1, T2>& p) {
    t1 = p.t1;
    t2 = p.t2;
}

template <typename T1, typename T2>
T1& Pair<T1, T2>::first() {
    return t1;
}

template <typename T1, typename T2>
T2& Pair<T1, T2>::second() {
    return t2;
}

#endif  // PAIR_H_

winec.h:

#ifndef WINEC_H_
#define WINEC_H_

#include <iostream>
#include <string>
#include <valarray>

#include "pair.h"

typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;

class Wine : private std::string, private PairArray {
    private:
    int years_num;

    public:
    Wine(const char* l, int y, const int yr[], const int bot[]);
    Wine(const char* l, int y);
    void GetBottles();
    const std::string& Label() const { return (std::string&)(*this); }
    int sum() const { return PairArray::second().sum(); }
    void Show() const;
};

#endif  // WINEC_H_

winec.cpp:

#include "winec.h"

Wine::Wine(const char* l, int y, const int yr[], const int bot[])
    : std::string(l),
years_num(y),
PairArray(ArrayInt(yr, y), ArrayInt(bot, y)) {}

Wine::Wine(const char* l, int y)
    : std::string(l), years_num(y), PairArray(ArrayInt(y), ArrayInt(y)) {}

void Wine::GetBottles() {
    int yn = 0;
    int b = 0;

    std::cout << "Enter " << Label() << " data for " << years_num << " year(s)"
        << std::endl;

    for (int i = 0; i < years_num; ++i) {
        std::cout << "Enter year: ";
        std::cin >> yn;
        PairArray::first()[i] = yn;
        std::cout << "Enter bottles for that year: ";
        std::cin >> b;
        PairArray::second()[i] = b;
    }
}

void Wine::Show() const {
    std::cout << "Wine: " << Label() << std::endl;
    std::cout << "Year  "
        << "  Bottles" << std::endl;
    for (int i = 0; i < years_num; ++i) {
        std::cout << PairArray::second()[i] << "    " << PairArray::first()[i]
            << std::endl;
    }
}

3. 定义一个QueueTp模板。然后在一个类似于程序清单14.12的程序中创建一个指向Worker的指针队列(参见程序清单14.10中的定义),并使用该队列来测试它。

worker.h:

#ifndef WORKER_H_
#define WORKER_H_

#include <string>

class Worker  // an abstract base class
{
    private:
    std::string fullname;
    long id;

    public:
    Worker() : fullname("none"), id(0L) {}
    Worker(const std::string& s, long n) : fullname(s), id(n) {}
    virtual ~Worker() {}
    virtual void Set();
    virtual void Show() const;
};

#endif  // WORKER_H_

worker.cpp:

#include "worker.h"

#include <iostream>

void Worker::Set() {
    std::cout << "Enter worker's name: ";
    getline(std::cin, fullname);
    std::cout << "Enter worker's ID: ";
    std::cin >> id;
    while (std::cin.get() != '\n') continue;
}

void Worker::Show() const {
    std::cout << "Name: " << fullname << "\n";
    std::cout << "Employee ID: " << id << "\n";
}

queueTp.h:

#ifndef QUEUETP_H_
#define QUEUETP_H_

template <typename T>
class QueueTp {
 private:
  enum { Q_SIZE = 10 };
  struct Node {
    T item;
    Node* next_ptr;
  };
  Node* front;
  Node* rear;
  int items;
  const int qsize;

 public:
  QueueTp(int qs = Q_SIZE);
  ~QueueTp();
  bool isempty() const { return items == 0; }
  bool isfull() const { return items == qsize; }
  int queuecount() const { return items; }
  bool push(const T& item);
  bool pop(T& item);
};

template <typename T>
QueueTp<T>::QueueTp(int qs) : qsize(qs) {
  front = rear = nullptr;
  items = 0;
}

template <typename T>
QueueTp<T>::~QueueTp() {
  Node* temp;
  while (front != nullptr) {
    temp = front;
    front = front->next_ptr;
    delete temp;
  }
}

template <typename T>
bool QueueTp<T>::push(const T& item) {
  if (isfull()) return false;
  Node* add = new Node;
  if (front == nullptr)  // if queue is empty
  {
    add->item = item;
    add->next_ptr = nullptr;
    front = rear = add;
  } else {
    add->item = item;
    add->next_ptr = nullptr;
    rear->next_ptr = add;
    rear = add;
  }
  items++;

  return true;
}

template <typename T>
bool QueueTp<T>::pop(T& item) {
  if (isempty()) return false;

  item = front->item;
  Node* temp;
  temp = front;
  front = front->next_ptr;
  delete temp;
  items--;

  return true;
}

#endif  // QUEUETP_H_

main.cpp:

#include <cstring>
#include <iostream>

#include "queueTp.h"
#include "worker.h"

int main() {
  using std::cin;
  using std::cout;
  using std::endl;
  using std::strchr;

  QueueTp<Worker> q(3);

  int count = 0;
  Worker* pWorker = new Worker[3];
  pWorker[0] = Worker("Jack", 000001);
  pWorker[1] = Worker("Toou", 000002);
  pWorker[2] = Worker("Boub", 000003);

  while (q.queuecount() < 3) {
    pWorker[count].Show();
    q.push(pWorker[count++]);
  }
  if (q.queuecount() == 3)
    std::cout << "The Queue is full, the elements are: \n";

  while (q.queuecount() > 0) {
    pWorker[--count].Show();
    q.pop(pWorker[count]);
  }
  if (q.queuecount() == 0) std::cout << "The Queue is empty now. \n";
  delete[] pWorker;

  return 0;
}

4. Person类保存人的名和姓。除构造函数外,它还有Show()方法,用于显示名和姓。Gunslinger类以Person类为虚基类派生而来,它包含一个Draw()成员,该方法返回一个double值,表示枪手的拔枪时间。这个类还包含一个int成员,表示枪手枪上的刻痕数。最后,这个类还包含一个Show()函数,用于显示所有这些信息。PokerPlayer类以Person类为虚基类派生而来。它包含一个Draw()成员,该函数返回一个1~52的随机数,用于表示扑克牌的值(也可以定义一个Card类,其中包含花色和面值成员,然后让Draw()返回一个Card对象)。PokerPlayer类使用Person类的show()函数。BadDude()类从GunslingerPokerPlayer类公有派生而来。它包含Gdraw()成员(返回坏蛋拔枪的时间)和Cdraw()成员(返回下一张扑克牌),另外还有一个合适的Show()函数。请定义这些类和方法以及其他必要的方法(如用于设置对象值的方法),并使用一个类似于程序清单14.12的简单程序对它们进行测试。

person.h:

#ifndef PERSON_H_
#define PERSON_H_

#include <string>

class Person {
    private:
    std::string firstname;
    std::string lastname;

    protected:
    virtual void Data() const;

    public:
    Person(const char* fn = "none", const char* ln = "none")
        : firstname(fn), lastname(ln) {}
    // no explicit copy constructor function
    virtual ~Person() {}
    virtual void Show() const;
    virtual void Set();
};

#endif  // PERSON_H_

person.cpp:

#include "person.h"

#include <iostream>

void Person::Data() const {
    std::cout << firstname << ", " << lastname << std::endl;
}

void Person::Show() const { Data(); }

void Person::Set() {
    std::cout << "Enter firstname: ";
    std::cin >> firstname;
    std::cout << "Enter lastname: ";
    std::cin >> lastname;
}

pokerplayer.h:

#ifndef POKERPLAYER_H_
#define POKERPLAYER_H_

#include "person.h"

class PokerPlayer : virtual public Person {
 public:
  PokerPlayer(const char* fn = "none", const char* ln = "none")
      : Person(fn, ln) {}
  int Draw() const;
};

#endif  // POKERPLAYER_H_

pokerplayer.cpp:

#include "pokerplayer.h"

#include <cstdlib>
#include <ctime>

int PokerPlayer::Draw() const {
    srand(time(0));
    return int(rand()) % 52 + 1;
}

gunslinger.h:

#ifndef GUNSLINGER_H_
#define GUNSLINGER_H_

#include "person.h"

class Gunslinger : virtual public Person {
    private:
    double drawtime;
    int notches;

    protected:
    void Data() const;

    public:
    Gunslinger(const char* fn = "none", const char* ln = "none", double d = 0.0,
               int n = 0)
        : Person(fn, ln), drawtime(d), notches(n) {}
    double Draw() const { return drawtime; }
    double Notches() const { return notches; }
    void Show() const;
    void Set();
};

#endif  // GUNSLINGER_H_

gunslinger.cpp:

#include "gunslinger.h"

#include <iostream>

void Gunslinger::Data() const {
    std::cout << "Draw: " << drawtime << std::endl;
    std::cout << "Notches: " << notches << std::endl;
}

void Gunslinger::Show() const {
    Person::Data();
    Data();
}

void Gunslinger::Set() {
    Person::Set();
    std::cout << "Enter Drawtime: ";
    std::cin >> drawtime;
    std::cout << "Enter Notches: ";
    std::cin >> notches;
}

baddude.h:

#ifndef BADDUDE_H_
#define BADDUDE_H_

#include "gunslinger.h"
#include "pokerplayer.h"

class BadDude : public PokerPlayer, public Gunslinger {
    protected:
    void Data() const;

    public:
    double Gdraw() const { return Gunslinger::Draw(); }
    double Cdraw() const { return PokerPlayer::Draw(); }
    void Show() const;
    void Set();
};

#endif  // BADDUDE_H_

baddude.cpp:

#include "baddude.h"

void BadDude::Data() const {
  Gunslinger::Data();
  PokerPlayer::Data();
}

void BadDude::Show() const { Data(); }

void BadDude::Set() { Gunslinger::Set(); }

main.cpp:

#include <cstring>
#include <iostream>

#include "baddude.h"
#include "gunslinger.h"
#include "person.h"
#include "pokerplayer.h"

const int SIZE = 5;

int main() {
    using namespace std;
    int ct, i;
    Person* gang[SIZE];

    for (ct = 0; ct < SIZE; ct++) {
        char choice;
        cout << "Enter the gang category: \n"
            << "o: ordinary person  g: gunslinger  "
            << "p: pokerplayer  b: bad dude  q: quit \n";
        cin >> choice;
        while (strchr("ogpbq", choice) == NULL) {
            cout << "Please enter an o, g, p, b, or q: ";
            cin >> choice;
        }

        if (choice == 'q') break;

        switch (choice) {
            case 'o':
                gang[ct] = new Person;
                break;
            case 'g':
                gang[ct] = new Gunslinger;
                break;
            case 'p':
                gang[ct] = new PokerPlayer;
                break;
            case 'b':
                gang[ct] = new BadDude;
                break;
        }

        cin.get();
        gang[ct]->Set();
    }

    cout << "\nHere is your gang: \n";
    for (i = 0; i < ct; i++) {
        cout << endl;
        gang[i]->Show();
    }
    for (i = 0; i < ct; i++) delete gang[i];
    cout << "Bye" << endl;

    return 0;
}

5. 下面是一些类声明:

// emp.h -- header file for abstr_emp class and children
#include <iostream>
#include <string>
class abstr_emp
{
    private:
    std::string fname; // abstr_emp's first name
    std::string lname; // abstr_emp's last name
    std::string job;
    public:
    abstr_emp();
    abstr_emp(const std::string & fn, const std::string & ln,
              const std::string & j);
    virtual void ShowAll() const; // labels and shows all data
    virtual void SetAll(); // prompts user for values
    friend std::ostream &
        operator<<(std::ostream & os, const abstr_emp & e);
    // just displays first and last name
    virtual ~abstr_emp() = 0; // virtual base class
};
class employee : public abstr_emp
{
    public:
    employee();
    employee(const std::string & fn, const std::string & ln,
             const std::string & j);
    virtual void ShowAll() const;
    virtual void SetAll();
};
class manager: virtual public abstr_emp
{
    private:
    int inchargeof; // number of abstr_emps managed
    protected:
    int InChargeOf() const { return inchargeof; } // output
    int & InChargeOf(){ return inchargeof; } // input
    public:
    manager();
    manager(const std::string & fn, const std::string & ln,
            const std::string & j, int ico = 0);
    manager(const abstr_emp & e, int ico);
    manager(const manager & m);
    virtual void ShowAll() const;
    virtual void SetAll();
};
class fink: virtual public abstr_emp
{
    private:
    std::string reportsto; // to whom fink reports
    protected:
    const std::string ReportsTo() const { return reportsto; }
    std::string & ReportsTo(){ return reportsto; }
    public:
    fink();
    fink(const std::string & fn, const std::string & ln,
         const std::string & j, const std::string & rpo);
    fink(const abstr_emp & e, const std::string & rpo);
    fink(const fink & e);
    virtual void ShowAll() const;
    virtual void SetAll();
};
class highfink: public manager, public fink // management fink
{
    public:
    highfink();
    highfink(const std::string & fn, const std::string & ln,
             const std::string & j, const std::string & rpo,
             int ico);
    highfink(const abstr_emp & e, const std::string & rpo, int ico);
    highfink(const fink & f, int ico);
    highfink(const manager & m, const std::string & rpo);
    highfink(const highfink & h);
    virtual void ShowAll() const;
    virtual void SetAll();
};

注意,该类层次结构使用了带虚基类的MI,所以要牢记这种情况下用于构造函数初始化列表的特殊规则。还需要注意的是,有些方法被声明为保护的。这可以简化一些highfink方法的代码(例如,如果highfink::ShowAll()只是调用fink::ShowAll()manager::ShwAll(),则它将调用abstr_emp::ShowAll()两次)。请提供类方法的实现,并在一个程序中对这些类进行测试。下面是一个小型测试程序:

// pe14-5.cpp
// useemp1.cpp -- using the abstr_emp classes
#include <iostream>
using namespace std;
#include "emp.h"
int main(void)
{
    employee em("Trip", "Harris", "Thumper");
    cout << em << endl;
    em.ShowAll();
    manager ma("Amorphia", "Spindragon", "Nuancer", 5);
    cout << ma << endl;
    ma.ShowAll();
    fink fi("Matt", "Oggs", "Oiler", "Juno Barr");
    cout << fi << endl;
    fi.ShowAll();
    highfink hf(ma, "Curly Kew"); // recruitment?
    hf.ShowAll();
    cout << "Press a key for next phase:\n";
    cin.get();
    highfink hf2;
    hf2.SetAll();
    cout << "Using an abstr_emp * pointer:\n";
    abstr_emp * tri[4] = {&em, &fi, &hf, &hf2};
    for (int i = 0; i < 4; i++)
        tri[i]->ShowAll();
    return 0;
}

类方法的实现:emp.cpp:

#include "emp.h"

/********abstr_emp**********/

abstr_emp::abstr_emp() {
    fname = "none";
    lname = "none";
    job = "none";
}

abstr_emp::abstr_emp(const std::string& fn, const std::string& ln,
                     const std::string& j)
    : fname(fn), lname(ln), job(j) {}

abstr_emp::~abstr_emp() {}

void abstr_emp::ShowAll() const {
    std::cout << "firstname: " << fname << std::endl;
    std::cout << "lastname: " << lname << std::endl;
    std::cout << "job: " << job << std::endl;
}

void abstr_emp::SetAll() {
    std::cout << "Enter firstname: ";
    std::getline(std::cin, fname);
    std::cout << "Enter lastname: ";
    std::getline(std::cin, lname);
    std::cout << "Enter job: ";
    std::getline(std::cin, job);
}

std::ostream& operator<<(std::ostream& os, const abstr_emp& e) {
    os << e.lname << " " << e.fname << ", " << e.job;
    return os;
}

/********employee**********/

employee::employee() {}

employee::employee(const std::string& fn, const std::string& ln,
                   const std::string& j)
    : abstr_emp(fn, ln, j) {}

void employee::ShowAll() const { abstr_emp::ShowAll(); }

void employee::SetAll() { abstr_emp::SetAll(); }

/********manager**********/

manager::manager() { inchargeof = 0; }

manager::manager(const std::string& fn, const std::string& ln,
                 const std::string& j, int ico)
    : abstr_emp(fn, ln, j), inchargeof(ico) {}

manager::manager(const abstr_emp& e, int ico) : abstr_emp(e) {
    inchargeof = ico;
}

manager::manager(const manager& m) : abstr_emp(m) { inchargeof = m.inchargeof; }

void manager::ShowAll() const {
    abstr_emp::ShowAll();
    std::cout << "Inchargeof: " << inchargeof << std::endl;
}

void manager::SetAll() {
    abstr_emp::SetAll();
    std::cout << "Enter inchargeof: ";
    std::cin >> inchargeof;
    std::cin.get();
}

/********fink**********/

fink::fink() { reportsto = "none"; }

fink::fink(const std::string& fn, const std::string& ln, const std::string& j,
           const std::string& rpo)
    : abstr_emp(fn, ln, j), reportsto(rpo) {}

fink::fink(const abstr_emp& e, const std::string& rpo)
    : abstr_emp(e), reportsto(rpo) {}

fink::fink(const fink& f) : abstr_emp(f) { reportsto = f.reportsto; }

void fink::ShowAll() const {
    abstr_emp::ShowAll();
    std::cout << "Reportsto: " << reportsto << std::endl;
}

void fink::SetAll() {
    abstr_emp::SetAll();
    std::cout << "Enter reportsto: ";
    std::getline(std::cin, reportsto);
}

/********highfink**********/

highfink::highfink() {}

highfink::highfink(const std::string& fn, const std::string& ln,
                   const std::string& j, const std::string& rpo, int ico)
    : abstr_emp(fn, ln, j), manager(fn, ln, j, ico), fink(fn, ln, j, rpo) {}

highfink::highfink(const abstr_emp& e, const std::string& rpo, int ico)
    : abstr_emp(e), manager(e, ico), fink(e, rpo) {}

highfink::highfink(const fink& f, int ico)
    : abstr_emp(f), fink(f), manager((const abstr_emp&)f, ico) {}

highfink::highfink(const manager& m, const std::string& rpo)
    : abstr_emp(m), manager(m), fink((const abstr_emp&)m, rpo) {}

highfink::highfink(const highfink& h) : abstr_emp(h), manager(h), fink(h) {}

void highfink::ShowAll() const {
    abstr_emp::ShowAll();
    std::cout << "Inchargeof: " << manager::InChargeOf() << std::endl;
    std::cout << "Reportsto: " << fink::ReportsTo() << std::endl;
}

void highfink::SetAll() {
    abstr_emp::SetAll();
    std::cout << "Enter reportsto: ";
    std::getline(std::cin, fink::ReportsTo());
    std::cout << "Enter Inchargeof: ";
    std::cin >> manager::InChargeOf();
    std::cin.get();
}

为什么没有定义赋值运算符?

类中不存在指针成员,不需要深拷贝,使用默认的赋值操作即可。

为什么要将ShowAll()SetAll()定义为虚的?

因为派生类将修改基类中setAll()ShowAll()两个函数的行为。

为什么要将abstr_emp定义为虚基类?

虚基类使得highfinkmanagerfink继承过来,只包含一个abstr_emp对象的拷贝,节省空间并避免不必要的冲突。

为什么highfink类没有数据部分?

highfink类需要的的数据成员已经包含在了它的父类中。

为什么只需要一个operator<<()版本?

因为这里只显示基类中的三个成员,派生类基类中的基类部分将自动调用基类的友元函数。

如果使用下面的代码替换程序的结尾部分,将会发生什么情况?

abstr_emp tri[4] = {em, fi, hf, hf2};
for (int i = 0; i < 4; i++)
tri[i].ShowAll();

编译失败,抽象类不能实例化。可以通过将virtua ~abstr_emp() = 0改为virtual  ~abstr_emp();,即将abstr_emp变成非抽象类,可编译通过,此时em, fi, hf, hf2这四个派生类对象将被强制转化为基类,所以只调用基类的ShowAll()函数。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吻等离子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值