C++ Primier Plus(第六版) 第十四章 C++中的代码重用 编程练习答案
1. Wine类有一个string类对象成员(参见第4章)和一个Pair对象(参见本章);其中前者用于存储葡萄酒的名称,而后者有2个valarray<int>对象(参见本章),这两个2个valarray<int>对象分别保存了葡萄酒的酿造年份和该年生产的瓶数。例如,Pair的第1个valarray<int>对象可能为1998、1992和1996年,第二个valarray<int>对象可能为24、48和144瓶。Wine最好有一个int成员用于存储年数。另外,一些typedef可能有助于简化编程工作:
typedef std::valarray\<int> ArrayInt;
typedef Pair<ArrayInt,ArrayInt> PairArray;
这样, PairArray表示的是类型Pair<std::valarray<int>,std::valarray<int>>。使用包含来实现Wine类,并用一个简单的程序对其进行测试。Wine类应该有一个默认构造函数以及如下构造函数:
// intialize label to l, number of years to y
// vintage year to yr[], bottles to bot[]
Wine(const char * l, int y, const int yr[], const int bot[]);
// intialize label to l, number of years to y
// create array objects of length y
Wine(const char * l, int y);
Wine类应该有意v额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::cout;
using std::cin;
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 array 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, intialize 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: 1988Enter bottles for that year: 42Enter year: 1994
Enter bottles for that year: 58
Enter year: 1998Enter bottles for that year: 122Enter year: 2001Enter 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
本题不算难,但需要对valarray对象的方法比较熟悉,类Pair的定义与本章的定义一样,在实现构造函数时,笔者忘记给years赋值了,刚开始导致程序错误,后面初始化列表赋值后正确。本题使用的valarray方法有resize(); = {yr,size_t}; operator;,样例代码如下(测试代码为题目所给代码):
// wine.h -- definition of Wine class
#ifndef WINEC_H_
#define WINEC_H_
#include <string>
#include <valarray>
// template class Pair
template<typename T1, typename T2>
class Pair
{
private:
T1 t1;
T2 t2;
public:
T1 & first() { return t1; }
T2 & second() { return t2; }
T1 first() const { return t1; }
T2 second() const { return t2; }
Pair(const T1 & t1val, const T2 & t2val) : t1(t1val), t2(t2val) {}
Pair() {};
};
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArrayInt;
class Wine
{
private:
std::string name;
PairArrayInt pai;
int years;
public:
Wine(const char * l = "no one", int y = 0);
Wine(const char *l, int y, const int yr[], const int bot[]);
void GetBottles();
const std::string & Label() const { return name; }
int sum() const;
void Show() const;
};
#endif
// wine.cpp -- methods for Wine class
#include <iostream>
#include "winec.h"
// constructor
Wine::Wine(const char * l, int y) : name(l), years(y)
{
pai.first().resize(years);
pai.second().resize(years);
}
Wine::Wine(const char *l, int y, const int yr[], const int bot[])
: name(l), years(y)
{
pai.first() = {yr, (long long unsigned int)years};
pai.second() = {bot, (long long unsigned int)years};
}
// input the bottles
void Wine::GetBottles()
{
std::cout << "Enter " << Label() << " data for "
<< years << " year(s): " << std::endl;
for (int i = 0; i < years; i++)
{
std::cout << "Enter year: ";
std::cin >> pai.first().operator[](i);
std::cout << "Enter bottles for that year: ";
std::cin >> pai.second().operator[](i);
}
// get all '\n'
while (std::cin.get() != '\n')
continue;
}
int Wine::sum() const
{
return pai.second().sum();
}
void Wine::Show() const
{
std::cout << "Wine: " << Label() << std::endl;
std::cout << "\t\tYear\tBottles" << std::endl;
for (int i = 0; i < years; i++)
std::cout << "\t\t" << pai.first()[i]
<< "\t" << pai.second()[i] << std::endl;
}
// ps: Wine::years forget to intialize
运行结果如下:
2.采用私有继承而不是包含来完成编程练习1。同样,一些typedef可能会有所帮助,另外,您可能还需要考虑诸如下面这样的语句的含义:
PairArray::operator = (PairArray(Arrayint(),ArrayInt()));
cout << (const string &) (*this);
您设计的类应该可以使用编程练习1中的测试程序进行测试。
本题将包含的关系转换成私有继承,头文件部分修改的程序不多,类方法实现部分主要修改的是构造函数,两个构造函数采用列表初始化的方法。代码如下:
// wine.h -- definition of Wine class
#ifndef WINEC_H_
#define WINEC_H_
#include <string>
#include <valarray>
// template class Pair
template<typename T1, typename T2>
class Pair
{
private:
T1 t1;
T2 t2;
public:
T1 & first() { return t1; }
T2 & second() { return t2; }
T1 first() const { return t1; }
T2 second() const { return t2; }
Pair(const T1 & t1val, const T2 & t2val) : t1(t1val), t2(t2val) {}
Pair() {};
};
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArrayInt;
class Wine : private std::string, private PairArrayInt
{
private:
int years;
public:
Wine(const char * l = "no one", int y = 0);
Wine(const char *l, int y, const int yr[], const int bot[]);
void GetBottles();
const std::string & Label() const { return (const std::string &) *this; }
int sum() const;
void Show() const;
};
#endif
// wine.cpp -- methods for Wine class
#include <iostream>
#include "winei.h"
// constructor
Wine::Wine(const char * l, int y) : std::string(l), years(y),
Pair(ArrayInt(y),ArrayInt(y)) { }
Wine::Wine(const char *l, int y, const int yr[], const int bot[])
: std::string(l), years(y),
Pair(ArrayInt{yr,(long long unsigned int)y}, ArrayInt{bot, (long long unsigned int)y}) { }
// input the bottles
void Wine::GetBottles()
{
std::cout << "Enter " << Label() << " data for "
<< years << " year(s): " << std::endl;
for (int i = 0; i < years; i++)
{
std::cout << "Enter year: ";
std::cin >> Pair::first().operator[](i);
std::cout << "Enter bottles for that year: ";
std::cin >> Pair::second().operator[](i);
}
// get all '\n'
while (std::cin.get() != '\n')
continue;
}
int Wine::sum() const
{
return Pair::second().sum();
}
void Wine::Show() const
{
std::cout << "Wine: " << Label() << std::endl;
std::cout << "\t\tYear\tBottles" << std::endl;
for (int i = 0; i < years; i++)
std::cout << "\t\t" << Pair::first()[i]
<< "\t" << Pair::second()[i] << std::endl;
}
// pe14-2.cpp -- using Wine class with inhetitance
#include <iostream>
#include "winei.h"
int main(void)
{
using std::cout;
using std::cin;
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 array 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, intialize 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;
}
运行结果如下:
3. 定义一个QueueTP模板。然后在一个类似于程序清单14.12的程序中创建一个Worker的指针队列(参见程序清单14.10中的定义),并使用该队列来测试它。
本题考查的是定义队列模板,同时用该队列管理指针。程序编写时没有遇到问题,但是编译时,程序遇到了错误,错误提示没有定义qcout,但是定义了,猜测是生成特定类时,该类的定义没有与Worker类关联起来。有两种修改方式,一种是将两个头文件定义在queuetp.h中。另一种方法是在queue.h中包含workermi.h的头文件,这样便可以解决该问题。测试代码以Worker的测试代码为样板,稍微修改了一下,代码如下:
// definition and methods for QueueTP class
#ifndef QUEUETP_H_
#define QUEUETP_H_
#include "workermi.h"
// template class definition
template <class T>
class QueueTP
{
private:
struct Node
{
T item;
struct Node * next;
};
Node * front;
Node * rear;
enum {SIZE = 10};
int qcount;
int qsize;
QueueTP(const QueueTP & q):qsize(0){}
QueueTP & operator=(const QueueTP & q){return * this;}
public:
QueueTP(int size = SIZE);
~QueueTP();
bool isemptey() { return qcount == 0; }
bool isfull() { return qcount == qsize; }
bool enqueue(const T & t );
bool dequeue(T & t);
};
// methods for QueueTP class
template <class T>
QueueTP<T>::QueueTP(int size) : qsize(size)
{
front = rear = nullptr;
qcount = 0;
}
template <class T>
QueueTP<T>::~QueueTP()
{
while(qcount != 0)
{
Node * temp;
temp = front;
front = front->next;
delete temp;
qcount--;
}
}
template <class T>
bool QueueTP<T>::enqueue(const T & t)
{
if (qcount < qsize)
{
if (isemptey())
{
Node * create = new Node;
create->item = t;
create->next = nullptr;
front = rear = create;
qcount++;
return true;
}
else
{
Node * create = new Node;
create->item = t;
create->next = nullptr;
rear->next = create;
rear = create;
qcount++;
return false;
}
}
else
return false;
}
template <class T>
bool QueueTP<T>::dequeue(T & t)
{
if (qcount > 0)
{
Node * temp;
t = front->item;
temp = front;
front = front->next;
delete temp;
qcount--;
return true;
}
else
return false;
}
#endif
// 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];
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 inhertitance
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 Worker & wk, int p = 0)
: Worker(wk), Waiter(wk, p), Singer(wk) {}
void Set();
void Show() const;
};
#endif
// workermi11.cpp -- working class methods with MI
#include "queuetp.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 Woker'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 the waiters's panache rating: ";
cin >> panache;
while (cin.get() != '\n')
continue;
}
// Singer methods
char * Singer::pv[Vtypes] = {"other", "alto", "contralto",
"soprano", "bass", "baritone", "tentor"};
void Singer::Set()
{
cout << "Enter the singer's name: ";
Worker::Get();
Singer::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 << endl;
cin >> voice;
while (cin.get() != '\n')
continue;
}
// SingingWaiter methods
void SingingWaiter::Data() const
{
Waiter::Data();
Singer::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 << "Catagory: singing waiter\n";
Worker::Data();
Data();
}
// workmi12.cpp -- multiple inheritance
// compile with workermi.cpp
#include <iostream>
#include <cstring>
#include "queuetp.h"
const int SIZE = 5;
int main()
{
using std::cin;
using std::cout;
using std::endl;
using std::strchr;
QueueTP<Worker *> qlolas(SIZE);
int ct;
Worker * lolas[SIZE];
for (ct = 0; ct < SIZE; ct++)
{
char choice;
cout << "Enter the employmee catagory:\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;
qlolas.enqueue(lolas[ct]);
break;
case 's': lolas[ct] = new Singer;
qlolas.enqueue(lolas[ct]);
break;
case 't': lolas[ct] = new SingingWaiter;
qlolas.enqueue(lolas[ct]);
break;
default:
break;
}
cin.get();
lolas[ct]->Set();
}
cout << "\nHere is your staff:\n";
int i;
for (i = 0; i < ct; i++)
{
Worker * temp;
qlolas.dequeue(temp);
temp->Show();
}
for (i = 0; i < ct; i++)
delete lolas[i];
cout << "Bye.\n";
return 0;
}
运行结果如下:
------------恢复内容开始------------
1. Wine类有一个string类对象成员(参见第4章)和一个Pair对象(参见本章);其中前者用于存储葡萄酒的名称,而后者有2个valarray<int>对象(参见本章),这两个2个valarray<int>对象分别保存了葡萄酒的酿造年份和该年生产的瓶数。例如,Pair的第1个valarray<int>对象可能为1998、1992和1996年,第二个valarray<int>对象可能为24、48和144瓶。Wine最好有一个int成员用于存储年数。另外,一些typedef可能有助于简化编程工作:
typedef std::valarray\<int> ArrayInt;
typedef Pair<ArrayInt,ArrayInt> PairArray;
这样, PairArray表示的是类型Pair<std::valarray<int>,std::valarray<int>>。使用包含来实现Wine类,并用一个简单的程序对其进行测试。Wine类应该有一个默认构造函数以及如下构造函数:
// intialize label to l, number of years to y
// vintage year to yr[], bottles to bot[]
Wine(const char * l, int y, const int yr[], const int bot[]);
// intialize label to l, number of years to y
// create array objects of length y
Wine(const char * l, int y);
Wine类应该有意v额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::cout;
using std::cin;
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 array 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, intialize 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: 1988Enter bottles for that year: 42Enter year: 1994
Enter bottles for that year: 58
Enter year: 1998Enter bottles for that year: 122Enter year: 2001Enter 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
本题不算难,但需要对valarray对象的方法比较熟悉,类Pair的定义与本章的定义一样,在实现构造函数时,笔者忘记给years赋值了,刚开始导致程序错误,后面初始化列表赋值后正确。本题使用的valarray方法有resize(); = {yr,size_t}; operator;,样例代码如下(测试代码为题目所给代码):
// wine.h -- definition of Wine class
#ifndef WINEC_H_
#define WINEC_H_
#include <string>
#include <valarray>
// template class Pair
template<typename T1, typename T2>
class Pair
{
private:
T1 t1;
T2 t2;
public:
T1 & first() { return t1; }
T2 & second() { return t2; }
T1 first() const { return t1; }
T2 second() const { return t2; }
Pair(const T1 & t1val, const T2 & t2val) : t1(t1val), t2(t2val) {}
Pair() {};
};
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArrayInt;
class Wine
{
private:
std::string name;
PairArrayInt pai;
int years;
public:
Wine(const char * l = "no one", int y = 0);
Wine(const char *l, int y, const int yr[], const int bot[]);
void GetBottles();
const std::string & Label() const { return name; }
int sum() const;
void Show() const;
};
#endif
// wine.cpp -- methods for Wine class
#include <iostream>
#include "winec.h"
// constructor
Wine::Wine(const char * l, int y) : name(l), years(y)
{
pai.first().resize(years);
pai.second().resize(years);
}
Wine::Wine(const char *l, int y, const int yr[], const int bot[])
: name(l), years(y)
{
pai.first() = {yr, (long long unsigned int)years};
pai.second() = {bot, (long long unsigned int)years};
}
// input the bottles
void Wine::GetBottles()
{
std::cout << "Enter " << Label() << " data for "
<< years << " year(s): " << std::endl;
for (int i = 0; i < years; i++)
{
std::cout << "Enter year: ";
std::cin >> pai.first().operator[](i);
std::cout << "Enter bottles for that year: ";
std::cin >> pai.second().operator[](i);
}
// get all '\n'
while (std::cin.get() != '\n')
continue;
}
int Wine::sum() const
{
return pai.second().sum();
}
void Wine::Show() const
{
std::cout << "Wine: " << Label() << std::endl;
std::cout << "\t\tYear\tBottles" << std::endl;
for (int i = 0; i < years; i++)
std::cout << "\t\t" << pai.first()[i]
<< "\t" << pai.second()[i] << std::endl;
}
// ps: Wine::years forget to intialize
运行结果如下:
2.采用私有继承而不是包含来完成编程练习1。同样,一些typedef可能会有所帮助,另外,您可能还需要考虑诸如下面这样的语句的含义:
PairArray::operator = (PairArray(Arrayint(),ArrayInt()));
cout << (const string &) (*this);
您设计的类应该可以使用编程练习1中的测试程序进行测试。
本题将包含的关系转换成私有继承,头文件部分修改的程序不多,类方法实现部分主要修改的是构造函数,两个构造函数采用列表初始化的方法。代码如下:
// wine.h -- definition of Wine class
#ifndef WINEC_H_
#define WINEC_H_
#include <string>
#include <valarray>
// template class Pair
template<typename T1, typename T2>
class Pair
{
private:
T1 t1;
T2 t2;
public:
T1 & first() { return t1; }
T2 & second() { return t2; }
T1 first() const { return t1; }
T2 second() const { return t2; }
Pair(const T1 & t1val, const T2 & t2val) : t1(t1val), t2(t2val) {}
Pair() {};
};
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArrayInt;
class Wine : private std::string, private PairArrayInt
{
private:
int years;
public:
Wine(const char * l = "no one", int y = 0);
Wine(const char *l, int y, const int yr[], const int bot[]);
void GetBottles();
const std::string & Label() const { return (const std::string &) *this; }
int sum() const;
void Show() const;
};
#endif
// wine.cpp -- methods for Wine class
#include <iostream>
#include "winei.h"
// constructor
Wine::Wine(const char * l, int y) : std::string(l), years(y),
Pair(ArrayInt(y),ArrayInt(y)) { }
Wine::Wine(const char *l, int y, const int yr[], const int bot[])
: std::string(l), years(y),
Pair(ArrayInt{yr,(long long unsigned int)y}, ArrayInt{bot, (long long unsigned int)y}) { }
// input the bottles
void Wine::GetBottles()
{
std::cout << "Enter " << Label() << " data for "
<< years << " year(s): " << std::endl;
for (int i = 0; i < years; i++)
{
std::cout << "Enter year: ";
std::cin >> Pair::first().operator[](i);
std::cout << "Enter bottles for that year: ";
std::cin >> Pair::second().operator[](i);
}
// get all '\n'
while (std::cin.get() != '\n')
continue;
}
int Wine::sum() const
{
return Pair::second().sum();
}
void Wine::Show() const
{
std::cout << "Wine: " << Label() << std::endl;
std::cout << "\t\tYear\tBottles" << std::endl;
for (int i = 0; i < years; i++)
std::cout << "\t\t" << Pair::first()[i]
<< "\t" << Pair::second()[i] << std::endl;
}
// pe14-2.cpp -- using Wine class with inhetitance
#include <iostream>
#include "winei.h"
int main(void)
{
using std::cout;
using std::cin;
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 array 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, intialize 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;
}
运行结果如下:
3. 定义一个QueueTP模板。然后在一个类似于程序清单14.12的程序中创建一个Worker的指针队列(参见程序清单14.10中的定义),并使用该队列来测试它。
本题考查的是定义队列模板,同时用该队列管理指针。程序编写时没有遇到问题,但是编译时,程序遇到了错误,错误提示没有定义qcout,但是定义了,猜测是生成特定类时,该类的定义没有与Worker类关联起来。有两种修改方式,一种是将两个头文件定义在queuetp.h中。另一种方法是在queue.h中包含workermi.h的头文件,这样便可以解决该问题。测试代码以Worker的测试代码为样板,稍微修改了一下,代码如下:
// definition and methods for QueueTP class
#ifndef QUEUETP_H_
#define QUEUETP_H_
#include "workermi.h"
// template class definition
template <class T>
class QueueTP
{
private:
struct Node
{
T item;
struct Node * next;
};
Node * front;
Node * rear;
enum {SIZE = 10};
int qcount;
int qsize;
QueueTP(const QueueTP & q):qsize(0){}
QueueTP & operator=(const QueueTP & q){return * this;}
public:
QueueTP(int size = SIZE);
~QueueTP();
bool isemptey() { return qcount == 0; }
bool isfull() { return qcount == qsize; }
bool enqueue(const T & t );
bool dequeue(T & t);
};
// methods for QueueTP class
template <class T>
QueueTP<T>::QueueTP(int size) : qsize(size)
{
front = rear = nullptr;
qcount = 0;
}
template <class T>
QueueTP<T>::~QueueTP()
{
while(qcount != 0)
{
Node * temp;
temp = front;
front = front->next;
delete temp;
qcount--;
}
}
template <class T>
bool QueueTP<T>::enqueue(const T & t)
{
if (qcount < qsize)
{
if (isemptey())
{
Node * create = new Node;
create->item = t;
create->next = nullptr;
front = rear = create;
qcount++;
return true;
}
else
{
Node * create = new Node;
create->item = t;
create->next = nullptr;
rear->next = create;
rear = create;
qcount++;
return false;
}
}
else
return false;
}
template <class T>
bool QueueTP<T>::dequeue(T & t)
{
if (qcount > 0)
{
Node * temp;
t = front->item;
temp = front;
front = front->next;
delete temp;
qcount--;
return true;
}
else
return false;
}
#endif
// 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];
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 inhertitance
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 Worker & wk, int p = 0)
: Worker(wk), Waiter(wk, p), Singer(wk) {}
void Set();
void Show() const;
};
#endif
// workermi11.cpp -- working class methods with MI
#include "queuetp.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 Woker'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 the waiters's panache rating: ";
cin >> panache;
while (cin.get() != '\n')
continue;
}
// Singer methods
char * Singer::pv[Vtypes] = {"other", "alto", "contralto",
"soprano", "bass", "baritone", "tentor"};
void Singer::Set()
{
cout << "Enter the singer's name: ";
Worker::Get();
Singer::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 << endl;
cin >> voice;
while (cin.get() != '\n')
continue;
}
// SingingWaiter methods
void SingingWaiter::Data() const
{
Waiter::Data();
Singer::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 << "Catagory: singing waiter\n";
Worker::Data();
Data();
}
// workmi12.cpp -- multiple inheritance
// compile with workermi.cpp
#include <iostream>
#include <cstring>
#include "queuetp.h"
const int SIZE = 5;
int main()
{
using std::cin;
using std::cout;
using std::endl;
using std::strchr;
QueueTP<Worker *> qlolas(SIZE);
int ct;
Worker * lolas[SIZE];
for (ct = 0; ct < SIZE; ct++)
{
char choice;
cout << "Enter the employmee catagory:\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;
qlolas.enqueue(lolas[ct]);
break;
case 's': lolas[ct] = new Singer;
qlolas.enqueue(lolas[ct]);
break;
case 't': lolas[ct] = new SingingWaiter;
qlolas.enqueue(lolas[ct]);
break;
default:
break;
}
cin.get();
lolas[ct]->Set();
}
cout << "\nHere is your staff:\n";
int i;
for (i = 0; i < ct; i++)
{
Worker * temp;
qlolas.dequeue(temp);
temp->Show();
}
for (i = 0; i < ct; i++)
delete lolas[i];
cout << "Bye.\n";
return 0;
}
运行结果如下:
4.Person类保存人的名和姓。除构造函数外,它还有Show()方法,用于显式名和姓。Gunslinger类以Person类为虚基类派生而来,它包含一个Draw()成员,该方法返回一个double值,表示枪手拔枪时间。这个类还有一个int成员,表示枪手墙上的刻痕数。最后,这个类还包含一个Show()函数,用于显式所有这些信息。
PokerPlayer类以Person类虚基类派生而来。它包含一个Draw()成员,该函数返回一个1~52的随机数,用于表示扑克牌的值(也可以定义一个Card类,其中包含花色和面值成员,然后让Draw()返回一个Card对象)。PokerPlayer类使用Person类的Show()函数。请定义这些类和方法以及其他必要的方法(如用于设置对象值的方法),并使用一个类似程序清单14.12的简单程序对他们进行测试。
本题考查的是虚基类的多重继承,使用virtual就可以实现虚基类继承,定义了一个Card对象,使PokePlayer的draw()返回一个对象,代码如下:
// personmi.h -- definition Person class and using inheritance
#ifndef PERSONMI_H_
#define PERSONMI_H_
#include <string>
// class Person definition
class Person
{
private:
std::string firstname;
std::string lastname;
protected:
void Get();
void Data() const;
public:
Person(const std::string & fn, const std::string ln) : firstname(fn), lastname(ln) { }
Person() { }
virtual ~Person() { }
virtual void Set();
virtual void Show() const = 0;
// virtual void Draw() const;
};
class Gunslinger : virtual public Person
{
private:
double guns;
int noches;
protected:
void Get();
void Data() const;
public:
Gunslinger() { }
Gunslinger(const std::string & fn, const std::string ln, double g = 0.0, int n = 0) :
Person(fn, ln), guns(g), noches(n) { }
Gunslinger(const Person & p, double g, int n) : Person(p), guns(g), noches(n) { }
virtual double Draw() const { return guns; }
virtual void Set();
virtual void Show() const;
};
class Card
{
protected:
enum {heart, dianmond, spade, club};
enum {CTypes = 4,PNums = 13};
private:
static char * pc[CTypes];
static char * pp[PNums];
int pcolor;
int poke;
public:
Card();
Card(int c, int p) : pcolor(c), poke(p) { }
void Show() const;
};
class PokerPlayer : virtual public Person
{
private:
Card card;
protected:
void Get() {};
void Data() const;
public:
PokerPlayer() { }
PokerPlayer(const std::string & fn, const std::string ln, const Card & c) :
Person(fn,ln), card(c) {}
PokerPlayer(const Person & p, const Card & c) : Person(p), card(c) { }
PokerPlayer(const Person & p) : Person(p){ }
PokerPlayer(const std::string & fn, const std::string ln) :
Person(fn,ln) { }
virtual Card Draw() const { Card c; return c; }
virtual void Set();
virtual void Show() const;
};
class BadDude : public Gunslinger, public PokerPlayer
{
public:
BadDude() { }
BadDude(const std::string & fn, const std::string ln, const Card & c ,double g = 0.0, int n = 0) :
Person(fn, ln), PokerPlayer(fn, ln, c), Gunslinger(fn, ln, g, n) { }
BadDude(const Person & p, const Card & c ,double g = 0.0, int n = 0) :
Person(p), PokerPlayer(p, c), Gunslinger(p, g, n) { }
BadDude(const Person & p,double g = 0.0, int n = 0) :
Person(p), PokerPlayer(p), Gunslinger(p, g, n) { }
virtual void Set();
virtual void Show() const;
double Gdraw() const;
Card Cdraw() const;
};
#endif
// personmi.cpp -- methods for Person claa
#include <iostream>
#include <cstdlib> // for rand() and srand()
#include <ctime>
#include "personmi.h"
using std::cin;
using std::cout;
using std::endl;
// methods for Person class
void Person::Get()
{
cout << "Enter firstname: ";
cin >> firstname;
cout << "Enter lastname: ";
cin >> lastname;
}
void Person::Data() const
{
cout << "Name: " << lastname << ", " << firstname << endl;
}
void Person::Set()
{
Get();
}
void Person::Show() const
{
Data();
}
// methods for Gunlinger class
void Gunslinger::Get()
{
cout << "Enter the seconds of taking guns: ";
cin >> guns;
cout << "Enter the number of noches: ";
cin >> noches;
}
void Gunslinger::Data() const
{
cout << "Seconds: " << guns << endl;
cout << "Noches: " << noches << endl;
}
void Gunslinger::Set()
{
cout << "Category gunslinger:\n";
Person::Get();
Get();
}
void Gunslinger::Show() const
{
Person::Data();
Data();
}
// methods for Card class
char * Card::pc[CTypes] = {"heart", "dianmond", "spade", "club"};
char * Card::pp[PNums] = {"A", "2", "3", "4", "5", "6", "7", "8",
"9", "10", "J", "Q", "K"};
Card::Card()
{
srand(time(0));
pcolor = rand() % 4;
poke = rand() % 13;
}
void Card::Show() const
{
cout << "Card: " << pc[pcolor] << ' ' << pp[poke] << endl;
}
// methods for PokerPlayer class
void PokerPlayer::Data() const
{
card.Show();
}
void PokerPlayer::Set()
{
cout << "Category pokeplayer\n";
Person::Get();
Get();
}
void PokerPlayer::Show() const
{
Person::Show();
Show();
}
// methods for BadDude class
void BadDude::Set()
{
cout << "Category baddude\n";
Person::Get();
Gunslinger::Get();
PokerPlayer::Get();
}
void BadDude::Show() const
{
Person::Data();
Gunslinger::Data();
PokerPlayer::Data();
}
double BadDude::Gdraw() const
{
Gunslinger::Draw();
}
Card BadDude::Cdraw() const
{
PokerPlayer::Draw();
}
// test Person class and using MI
// compile with personmi.cpp
#include <iostream>
#include <cstring>
#include "personmi.h"
const int SIZE = 5;
int main()
{
using std::cout;
using std::cin;
using std::endl;
Person *p[SIZE];
int ct;
for (ct = 0; ct < SIZE; ct++)
{
char choice;
cout << "Enter the person category:\n";
cout << "g: gunslinger p: pokerplayer\n";
cout << "b: baddude q: quit\n";
while (cin >> choice && strchr("gpbq", choice) == NULL)
cout << "Please enter a g, p, b, q: ";
if (choice == 'q')
break;
switch(choice)
{
case 'g' : p[ct] = new Gunslinger;
break;
case 'p' : p[ct] = new PokerPlayer;
break;
case 'b' : p[ct] = new BadDude;
break;
default : break;
}
p[ct]->Set();
}
for (int i = 0; i < ct; i++)
{
p[i]->Show();
}
for (int i = 0; i < ct; i++)
delete p[i];
cout << "Done.\n";
return 0;
}
运行结果如下:
5. 下面是一些类声明:
#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, 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() const;
};
class manager : virtual public abstr_emp
{
private:
int inchargeof;
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() const;
};
class fink : virtual public abstr_emp
{
private:
std::string reportsto; // to whom fink reports
protected:
const std::string ReportsTo() const { return reportsto; }
const 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 fink & f);
virtual void ShowAll() const;
virtual void SetAll() const;
};
class highfink : public manager, public 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() const;
};
注意,该类层次结构使用了带虚基类的MI,所以要牢记这种情况下用于构造函数初始化列表的特殊规则。还需要注意的是,有些代码被声明为保护的。这可以简化一些highfink方法的代码(例如,如果highfink::ShowAll()只是调用fink::ShowAll()和manager::ShowAll(),则它将调用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", "Sprindragon", "Nuancer", 5);
cout << ma << endl;
ma.ShowAll();
fink fi("Matt", "Oggs", "Oiler", "Juno Barr");
cout << fi << endl;
fi.ShowAll();
highfink hf(ma, "Curly Kew");
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;
}
为什么没有定义赋值运算符?
为什么要将ShowAll()和SetAll()定义为虚的?
为什么要将abstr_emp定义为虚基类?
为什么highfink类没有数据部分?
为什么只需要一个operator<<()版本?
如果使用下面的代码替换掉程序的结尾部分,将会发生什么情况?
abstr_emp tri[4] = {em, fi, hf, hf2};
for (int i = 0; i < 4; i++)
tri[i].ShowAll();
因为highfink使用的是复制构造函数,而且没有动态分配内存,因此不需要重新定义赋值运算符。
为了实现ShowAll()和SetAll()的动态联编。
定义为虚基类才可以是highfink只有一个abstr_emp实例。
highfink类的数据成员都在基类中,因此没有数据部分。
其他派生类可以通过强制向上转换使用abstr_emp的operator<<()版本。
使用这些代码,将只输出名字和工作而不输出其他信息,因为对象无法进行强制向上转换。
本题考查的是虚基类MI的定义如何写,测试代码和头文件代码如题所示,MI实现的代码如下:
// emp.cpp -- methods for mi
#include "emp.h"
using std::cout;
using std::cin;
using std::endl;
// methods for abstr_class
abstr_emp::abstr_emp() { }
abstr_emp::abstr_emp(const std::string & fn, const std::string & ln,
const std::string & j) : fname(fn), lname(ln), job(j) { }
void abstr_emp::ShowAll() const
{
cout << "Name: " << lname << ", " << fname << endl;
cout << " Job: " << job << endl;
}
void abstr_emp::SetAll()
{
cout << "Enter firstname: ";
cin >> fname;
cout << "Enter lastname: ";
cin >> lname;
while (cin.get() != '\n')
continue;
cout << "Enter job: ";
getline(cin, job);
}
std::ostream & operator<<(std::ostream & os, abstr_emp & e)
{
os << e.lname << ", " << e.fname;
return os;
}
abstr_emp::~abstr_emp() { } // is necessary
// methods for employee class
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()
{
cout << "Category employee:\n";
abstr_emp::SetAll();
}
// methods for employee class
manager::manager() { }
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();
cout << " Number in charge of employees: " << inchargeof << endl;
}
void manager::SetAll()
{
cout << "Category manager:\n";
abstr_emp::SetAll();
cout << "Enter number of in charge of employees: ";
cin >> inchargeof;
while (cin.get() != '\n')
continue;
}
// methods for fink class
fink::fink() { }
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();
cout << " Reports to " << reportsto << endl;
}
void fink::SetAll()
{
cout << "Category fink:\n";
abstr_emp::SetAll();
cout << "Enter repeorts to : ";
getline(cin, reportsto);
}
// methods for highfink class
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 manager & m, const std::string & rpo) : abstr_emp(m),
manager(m), fink(m,rpo) { }
highfink::highfink(const fink & f, int ico) : abstr_emp(f), manager(f, ico),
fink(f) { }
highfink::highfink(const highfink & h) : abstr_emp(h), manager(h), fink(h) { }
void highfink::ShowAll() const
{
abstr_emp::ShowAll();
cout << " Number in charge of employees: " << manager::InChargeOf() << endl;
cout << " Reports to " << fink::ReportsTo() << endl;
}
void highfink::SetAll()
{
cout << "Category highfink:\n";
abstr_emp::SetAll();
int temp_ico;
cout << "Enter number of in charge of employees: ";
cin >> temp_ico;
manager::InChargeOf() = temp_ico;
while (cin.get() != '\n')
continue;
std::string temp_rpo;
cout << "Enter repeorts to : ";
getline(cin, temp_rpo);
fink::ReportsTo() = temp_rpo;
}
运行结果如下: