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类应该有一个默认构造函数以及如下构造函数:
Wine (const char * l, int y, const int yr[], const int bot[]);
Wine (const char * l, int y);
Wine类应该有意v额GetBottles()方法,它根据Wine对象能够存储几种年份(y),提醒用户输入年份和瓶数。方法Label放回一个指向葡萄酒名称的引用。sum()方法返回Pair对象中第二个valarray<int>对象中的瓶数总和。
测试程序应提示用户输入葡萄酒名称、元素个数以及每个元素存储的年份和瓶数等信息。程序将使用这些数据构造一个Wine对象,然后显式对象中保存的信息。
下面是一个简单的测试程序:
#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) ;
holding.GetBottles ();
holding.Show ();
const int YRS = 3 ;
int y[YRS] = {1993 , 1995 , 1998 };
int b[YRS] = { 48 , 60 , 72 };
Wine more ("Gushing Grape Red" , YRS, y, b) ;
more.Show ();
cout << "Total bottles for " << more.Label ()
<< ": " << more.sum () << endl;
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 ;,样例代码如下(测试代码为题目所给代码):
#ifndef WINEC_H_
#define WINEC_H_
#include <string>
#include <valarray>
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
#include <iostream>
#include "winec.h"
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};
}
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);
}
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;
}
运行结果如下:
2.采用私有继承而不是包含来完成编程练习1。同样,一些typedef可能会有所帮助,另外,您可能还需要考虑诸如下面这样的语句的含义:
PairArray::operator = (PairArray(Arrayint(),ArrayInt()));
cout << (const string &) (*this);
您设计的类应该可以使用编程练习1中的测试程序进行测试。
本题将包含的关系转换成私有继承,头文件部分修改的程序不多,类方法实现部分主要修改的是构造函数,两个构造函数采用列表初始化的方法。代码如下:
#ifndef WINEC_H_
#define WINEC_H_
#include <string>
#include <valarray>
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
#include <iostream>
#include "winei.h"
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}) { }
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);
}
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;
}
#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) ;
holding.GetBottles ();
holding.Show ();
const int YRS = 3 ;
int y[YRS] = {1993 , 1995 , 1998 };
int b[YRS] = { 48 , 60 , 72 };
Wine more ("Gushing Grape Red" , YRS, y, b) ;
more.Show ();
cout << "Total bottles for " << more.Label ()
<< ": " << more.sum () << endl;
cout << "Bye\n" ;
return 0 ;
}
运行结果如下:
3. 定义一个QueueTP模板。然后在一个类似于程序清单14.12的程序中创建一个Worker的指针队列(参见程序清单14.10中的定义),并使用该队列来测试它。
本题考查的是定义队列模板,同时用该队列管理指针。程序编写时没有遇到问题,但是编译时,程序遇到了错误,错误提示没有定义qcout,但是定义了,猜测是生成特定类时,该类的定义没有与Worker类关联起来。有两种修改方式,一种是将两个头文件定义在queuetp.h中。另一种方法是在queue.h中包含workermi.h的头文件,这样便可以解决该问题。测试代码以Worker的测试代码为样板,稍微修改了一下,代码如下:
#ifndef QUEUETP_H_
#define QUEUETP_H_
#include "workermi.h"
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) ;
};
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
#ifndef WORKERMI_H_
#define WORKERMI_H_
#include <string>
class Worker
{
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 ;
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 ;
};
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
#include "queuetp.h"
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
Worker::~Worker () {}
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 ;
}
void Waiter::Set ()
{
cout << "Enter waiter's name: " ;
Worker::Get ();
Get ();
}
void Waiter::Show () const
{
cout << "Category: waiter\n" ;
Worker::Data ();
Data ();
}
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 ;
}
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 ();
}
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 ;
}
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 ();
}
#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类应该有一个默认构造函数以及如下构造函数:
Wine (const char * l, int y, const int yr[], const int bot[]);
Wine (const char * l, int y);
Wine类应该有意v额GetBottles()方法,它根据Wine对象能够存储几种年份(y),提醒用户输入年份和瓶数。方法Label放回一个指向葡萄酒名称的引用。sum()方法返回Pair对象中第二个valarray<int>对象中的瓶数总和。
测试程序应提示用户输入葡萄酒名称、元素个数以及每个元素存储的年份和瓶数等信息。程序将使用这些数据构造一个Wine对象,然后显式对象中保存的信息。
下面是一个简单的测试程序:
#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) ;
holding.GetBottles ();
holding.Show ();
const int YRS = 3 ;
int y[YRS] = {1993 , 1995 , 1998 };
int b[YRS] = { 48 , 60 , 72 };
Wine more ("Gushing Grape Red" , YRS, y, b) ;
more.Show ();
cout << "Total bottles for " << more.Label ()
<< ": " << more.sum () << endl;
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 ;,样例代码如下(测试代码为题目所给代码):
#ifndef WINEC_H_
#define WINEC_H_
#include <string>
#include <valarray>
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
#include <iostream>
#include "winec.h"
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};
}
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);
}
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;
}
运行结果如下:
2.采用私有继承而不是包含来完成编程练习1。同样,一些typedef可能会有所帮助,另外,您可能还需要考虑诸如下面这样的语句的含义:
PairArray::operator = (PairArray(Arrayint(),ArrayInt()));
cout << (const string &) (*this);
您设计的类应该可以使用编程练习1中的测试程序进行测试。
本题将包含的关系转换成私有继承,头文件部分修改的程序不多,类方法实现部分主要修改的是构造函数,两个构造函数采用列表初始化的方法。代码如下:
#ifndef WINEC_H_
#define WINEC_H_
#include <string>
#include <valarray>
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
#include <iostream>
#include "winei.h"
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}) { }
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);
}
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;
}
#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) ;
holding.GetBottles ();
holding.Show ();
const int YRS = 3 ;
int y[YRS] = {1993 , 1995 , 1998 };
int b[YRS] = { 48 , 60 , 72 };
Wine more ("Gushing Grape Red" , YRS, y, b) ;
more.Show ();
cout << "Total bottles for " << more.Label ()
<< ": " << more.sum () << endl;
cout << "Bye\n" ;
return 0 ;
}
运行结果如下:
3. 定义一个QueueTP模板。然后在一个类似于程序清单14.12的程序中创建一个Worker的指针队列(参见程序清单14.10中的定义),并使用该队列来测试它。
本题考查的是定义队列模板,同时用该队列管理指针。程序编写时没有遇到问题,但是编译时,程序遇到了错误,错误提示没有定义qcout,但是定义了,猜测是生成特定类时,该类的定义没有与Worker类关联起来。有两种修改方式,一种是将两个头文件定义在queuetp.h中。另一种方法是在queue.h中包含workermi.h的头文件,这样便可以解决该问题。测试代码以Worker的测试代码为样板,稍微修改了一下,代码如下:
#ifndef QUEUETP_H_
#define QUEUETP_H_
#include "workermi.h"
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) ;
};
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
#ifndef WORKERMI_H_
#define WORKERMI_H_
#include <string>
class Worker
{
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 ;
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 ;
};
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
#include "queuetp.h"
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
Worker::~Worker () {}
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 ;
}
void Waiter::Set ()
{
cout << "Enter waiter's name: " ;
Worker::Get ();
Get ();
}
void Waiter::Show () const
{
cout << "Category: waiter\n" ;
Worker::Data ();
Data ();
}
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 ;
}
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 ();
}
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 ;
}
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 ();
}
#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()返回一个对象,代码如下:
#ifndef PERSONMI_H_
#define PERSONMI_H_
#include <string>
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 ;
};
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
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "personmi.h"
using std::cin;
using std::cout;
using std::endl;
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 ();
}
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 ();
}
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;
}
void PokerPlayer::Data () const
{
card.Show ();
}
void PokerPlayer::Set ()
{
cout << "Category pokeplayer\n" ;
Person::Get ();
Get ();
}
void PokerPlayer::Show () const
{
Person::Show ();
Show ();
}
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 ();
}
#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;
std::string lname;
std::string job;
public :
abstr_emp ();
abstr_emp (const std::string & fn, const std::string & ln,
const std::string & j);
virtual void ShowAll () const ;
virtual void SetAll () ;
friend std::ostream &
operator <<(std::ostream & os, abstr_emp & e);
virtual ~abstr_emp () = 0 ;
};
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; }
int & InChargeOf () { return inchargeof; }
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;
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()两次)。请提供类方法的实现,并在一个程序中对这些类进行测试。下面是一个小型测试程序:
#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实现的代码如下:
#include "emp.h"
using std::cout;
using std::cin;
using std::endl;
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 () { }
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 ();
}
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 ;
}
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);
}
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;
}
运行结果如下:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程