Wine类有一个string类对象成员(参见第4章)和一个Pair对象(参见本章):其中前者用来存储葡萄酒的名称,而后者有2个valarry对象(参见本章),这两个valarry对象分别保存了葡萄酒的酿造年份和该年生产的瓶数。例如,Pair的第1个valarray对象可能为1988、1992和1996,第二个valarry 对象可能为24、48和144瓶。Wine最好有1个int成员用于存储年数。另外,一些typedef可能有助于简化编程工作:
typedef std::valarry<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;
这样,PairArray表示的类型是Pair
Wine(const char* l, int y, const int yr[], ocnst int bot[]);
Wine(const char* l, int y);
Wine类应该有一个GetBottles()方法,它根据Wine对象能够存储集中年份(y),提示用户输入年份和瓶数。方法Label()返回一个指向葡萄酒名称的引用。sum()方法返回Pair对象中第二个valarray
测试程序应提示用户输入葡萄酒名称、元素个数以及每个元素存储的年份和瓶数等信息。程序将使用这些数据来构造一个Wine对象,然后显示对象中保存的信息。
下面是一个简单的测试程序:
#include
#include "winec.h"
using namespace std;
int main()
{
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 bottle 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: 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 bottle for Gushing Grape Red: 180
Bye
代码:
winec.h:
#ifndef WINEC_H_
#define WINEC_H_
#include
#include
#include
template <class T1, class T2>
class Pair
{
private:
T1 a;
T2 b;
public:
Pair(const T1 &aval, const T2 &bval) : a(aval), b(bval) {}
Pair() {}
void set(const T1 &yr, const T2 &bot);
int sum() const;
void Show(int y) const;
};
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;
class Wine
{
private:
std::string name;
PairArray b;
int yrs;
public:
Wine(const char *l, int y, const int yr[], const int bot[]);
Wine(const char *l, int y);
void GetBottles();
std::string &Label();
int sum() const;
void Show() const;
};
#endif
winec.cpp:
#include
#include
#include
#include "winec.h"
using namespace std;
template <class T1, class T2>
void Pair<T1, T2>::set(const T1 &yr, const T2 &bot)
{
a = yr;
b = bot;
}
template <class T1, class T2>
int Pair<T1, T2>::sum() const
{
return b.sum();
}
template <class T1, class T2>
void Pair<T1, T2>::Show(int y) const
{
for (int i = 0; i < y; i++)
{
cout << "\t\t" << a[i] << "\t\t" << b[i] << endl;
}
}
Wine::Wine(const char *l, int y, const int yr[], const int bot[])
{
name = l;
yrs = y;
b.set(ArrayInt(yr, yrs), ArrayInt(bot, yrs));
}
Wine::Wine(const char *l, int y)
{
name = l;
yrs = y;
}
void Wine::GetBottles()
{
ArrayInt yr(yrs), bot(yrs);
cout << "Enter " << name << " data for " << yrs << " year(s):\n";
for (int i = 0; i < yrs; i++)
{
cout << "Enter year: ";
cin >> yr[i];
cout << "Enter bottles for that year: ";
cin >> bot[i];
}
b.set(yr, bot);
}
std::string &Wine::Label()
{
return name;
}
int Wine::sum() const
{
return b.sum();
}
void Wine::Show() const
{
cout << "Wine: " << name << endl;
cout << "\t\tYear\t\tBottles\n";
b.Show(yrs);
}
运行结果:
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.1>g++ winec.cpp pe14-1.cpp -o pe14-1.exe
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.1>pe14-1
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 bottle for Gushing Grape Red: 180
Bye
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.1>
采用私有继承而不是包含来完成编程练习1。同样,一些typedef可能会有所帮助,另外,您可能还需要考虑诸如下面这样的语句的含义:
PairArray::operator=(PairArray(ArrayInt(), ArrayInt()));
cout << (const string&)(*this);
您设计的类应该可以使用编程练习1中的测试程序进行测试。
代码:
winep.h
#ifndef WINEP_H
#define WINEP_H
#include
#include
#include
template <class T1, class T2>
class Pair
{
private:
T1 a;
T2 b;
public:
Pair(const T1 &aval, const T2 &bval) : a(aval), b(bval) {}
Pair() {}
void set(const T1 &yr, const T2 &bot);
int sum() const;
void Show(int y) const;
};
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;
class Wine : private std::string, private PairArray
{
private:
int yrs;
public:
Wine(const char *l, int y, const int yr[], const int bot[]);
Wine(const char *l, int y);
void GetBottles();
std::string &Label();
int sum() const;
void Show() const;
};
#endif
winep.cpp:
#include
#include
#include
#include "winep.h"
using namespace std;
template <class T1, class T2>
void Pair<T1, T2>::set(const T1 &yr, const T2 &bot)
{
a = yr;
b = bot;
}
template <class T1, class T2>
int Pair<T1, T2>::sum() const
{
return b.sum();
}
template <class T1, class T2>
void Pair<T1, T2>::Show(int y) const
{
for (int i = 0; i < y; i++)
{
cout << "\t\t" << a[i] << "\t\t" << b[i] << endl;
}
}
Wine::Wine(const char *l, int y, const int yr[], const int bot[]) : string(l), yrs(y), PairArray(ArrayInt(yr, y), ArrayInt(bot, y))
{
}
Wine::Wine(const char *l, int y) : string(l), yrs(y)
{
}
void Wine::GetBottles()
{
ArrayInt yr(yrs), bot(yrs);
cout << "Enter" << (const string &)(*this) << " data for " << yrs << " year(s):\n";
for (int i = 0; i < yrs; i++)
{
cout << "Enter year: ";
cin >> yr[i];
cout << "Enter bottles for that year: ";
cin >> bot[i];
}
PairArray::set(yr, bot);
}
string &Wine::Label()
{
return (string &)(*this);
}
int Wine::sum() const
{
return PairArray::sum();
}
void Wine::Show() const
{
cout << "Wine: " << (const string &)(*this) << endl;
cout << "\t\tYear\t\tBottles\n";
PairArray::Show(yrs);
}
运行结果:
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.2>g++ winep.cpp pe14-2.cpp -o pe14-2.exe
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.2>pe14-2
Enter name of wine: Gully Wash
Enter number of years: 4
EnterGully 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 bottle for Gushing Grape Red: 180
Bye
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.2>
定义一个QueueTp模板。然后在一个类似于程序清单14.12的程序中创建一个指向Worker的指针队列(参见程序清单14.10中的定义),并使用该队列来测试它。
代码:
QueueTp.h:
#ifndef QUEUETP_H_
#define QUEUETP_H_
template <typename T>
class QueueTp
{
private:
static const int LEN = 10;
T *head;
T *tail;
T *data;
public:
QueueTp(int len = LEN)
{
data = new T[len];
head = tail = data;
}
~QueueTp() { delete[] data; }
bool enQueue(const T &item);
bool deQueue(T &item);
T newQueue() const { return *(tail - 1); }
bool isFull() const { return tail == data + sizeof(data); }
bool isEmpty() const { return tail == head; }
};
template <typename T>
bool QueueTp<T>::enQueue(const T &item)
{
if (isFull())
return false;
*tail = item;
tail++;
return true;
}
template <typename T>
bool QueueTp<T>::deQueue(T &item)
{
if (isFull())
return false;
item = *head;
head++;
return true;
}
#endif // !QUEUETP_H_
workermi.h:
#ifndef WORKERMI_H_
#define WORKERMI_H_
#include
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 &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_H_
workermi.cpp:
#include
#include "workermi.h"
using std::cin;
using std::cout;
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 worker'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 waiter's panache rating: ";
cin >> panache;
while (cin.get() != '\n')
continue;
}
char temp1[] = "other";
char temp2[] = "alto";
char temp3[] = "contralto";
char temp4[] = "soprano";
char temp5[] = "bass";
char temp6[] = "baritone";
char temp7[] = "tenor";
char *Singer::pv[Singer::Vtypes] = {temp1, temp2, temp3, temp4, temp5, temp6, temp7};
void Singer::Set()
{
cout << "Enter singer's name: ";
Worker::Get();
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
{
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();
}
main.cpp:
#include
#include
#include "workermi.h"
#include "QueueTP.h"
int main()
{
using std::cin;
using std::cout;
using std::endl;
using std::strchr;
QueueTp<Worker *> queue_worker;
int ct;
while (!queue_worker.isFull())
{
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':
queue_worker.enQueue(new Waiter);
break;
case 's':
queue_worker.enQueue(new Singer);
break;
case 't':
queue_worker.enQueue(new SingingWaiter);
break;
}
cin.get();
queue_worker.newQueue()->Set();
}
cout << "\nHere is your staff:\n";
Worker *wrk;
while (!queue_worker.isEmpty())
{
queue_worker.deQueue(wrk);
cout << endl;
wrk->Show();
delete wrk;
}
cout << "Bye.\n";
return 0;
}
运行结果:
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.3>g++ workermi.cpp main.cpp -o main
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.3>main
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.
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.3>
Person类保存人的名和姓。除构造函数外,它还有Show()方法,用于显示名和姓。Gunslmger类以Person类为虚基类派生而来,它包含一个Draw()成员,该方法返回一个double值,表示枪手的拔枪时间。这个类还包含一个int成员,表示枪手枪上的刻痕数。最后,这个类还包含一个Show()函数,用于显示所有这些信息。
PokerPlayer类以Person类为虚基类派生而来。它包含一个Draw()成员,该函数返回一个1~52的随机数,用于扑克牌的值(也可以用定义一个Card类,其中包含花色和面值成员,然后让Draw()返回一个Card对象)。PokerPlayer类使用Person类的show()函数。BadDude()类从Gunslinger何PokerPlayer类公有派生而来。它包含Gdraw()成员(返回坏蛋拔枪时间)和Cdraw()成员(返回下一张扑克牌),另外还有一个合适的show()函数。请定义这些类和方法以及其他必要的方法(如用于设置对象值的方法),并使用一些类似程序清单14.12的简单程序对它们进行测试。
代码:
person.h:
#ifndef PERSON_H_
#define PERSON_H_
#include
#include
class Person
{
private:
std::string fname; // 名
std::string lname; // 姓
protected:
virtual void Data() const;
virtual void Get();
public:
Person() : fname("Null"), lname("Null"){};
Person(std::string fname, std::string lname) : fname(fname), lname(lname){};
virtual ~Person() = 0;
virtual void Set() = 0;
virtual void Show() const = 0;
};
class Gunslinger : virtual public Person
{
private:
double time; // 拔枪时间
int num; // 枪上的刻痕数
protected:
void Data() const;
void Get();
public:
Gunslinger() : Person(), time(0.0), num(0){};
Gunslinger(std::string fn, std::string ln, double ti, int nu) : Person(fn, ln), time(ti), num(nu){};
Gunslinger(Person &p, double ti, int nu) : Person(p), time(ti), num(nu){};
double Draw() { return time; }
void Set();
void Show() const;
};
class PokerPlayer : virtual public Person
{
private:
int card; // 扑克牌的值
protected:
void Data() const;
void Get();
public:
PokerPlayer() : Person(), card(1){};
PokerPlayer(std::string fn, std::string ln, int ca) : Person(fn, ln), card(ca){};
PokerPlayer(Person &p, int ca) : Person(p), card(ca){};
int Draw() { return card; }
void Set();
void Show() const;
};
class BadDude : public Gunslinger, public PokerPlayer
{
protected:
void Data() const;
void Get();
public:
BadDude(){};
BadDude(std::string fn, std::string ln, double ti = 0.0, int nu = 0, int ca = 1)
: Person(fn, ln), Gunslinger(fn, ln, ti, nu), PokerPlayer(fn, ln, ca) {}
BadDude(Person &p, double ti, int nu, int ca)
: Person(p), Gunslinger(p, ti, nu), PokerPlayer(p, ca) {}
BadDude(Gunslinger &gs, int ca)
: Person(gs), Gunslinger(gs), PokerPlayer(gs, ca) {}
BadDude(PokerPlayer &pp, double ti, int nu)
: Person(pp), Gunslinger(pp, ti, nu), PokerPlayer(pp) {}
double Gdraw() { return Gunslinger::Draw(); }
int Cdraw() { return PokerPlayer::Draw(); }
void Set();
void Show() const;
};
#endif // !PERSON_H_
person.cpp:
#include
#include
#include "person.h"
using std::cin;
using std::cout;
using std::endl;
using std::string;
Person::~Person() {}
void Person::Data() const
{
cout << "First name: " << fname << endl;
cout << "Last name: " << lname << endl;
}
void Person::Get()
{
cout << "Enter person's first name: ";
getline(cin, fname);
cout << "Enter person's last name: ";
getline(cin, lname);
}
void Gunslinger::Data() const
{
cout << "Time: " << endl;
cout << "Num of scotch: " << endl;
}
void Gunslinger::Get()
{
cout << "Please enter time: " << endl;
cin >> time;
cout << "Please enter num of scotch: " << endl;
cin >> num;
while (cin.get() != '\n')
continue;
}
void Gunslinger::Set()
{
Person::Get();
Get();
cout << endl;
}
void Gunslinger::Show() const
{
cout << "Category: Gunslinger\n";
Person::Data();
Data();
}
void PokerPlayer::Data() const
{
cout << "Card: " << card << endl;
}
void PokerPlayer::Get()
{
cout << "Please enter card: " << endl;
cin >> card;
while (cin.get() != '\n')
continue;
}
void PokerPlayer::Set()
{
Person::Get();
Get();
cout << endl;
}
void PokerPlayer::Show() const
{
cout << "Category: PokerPlayer\n";
Person::Data();
Data();
}
void BadDude::Data() const
{
Gunslinger::Data();
PokerPlayer::Data();
}
void BadDude::Get()
{
Gunslinger::Get();
PokerPlayer::Get();
}
void BadDude::Set()
{
Person::Get();
Get();
cout << endl;
}
void BadDude::Show() const
{
Person::Data();
Data();
}
main.cpp:
#include
#include
#include "person.h"
using namespace std;
const int SIZE = 5;
int main()
{
Person *person[SIZE];
int ct;
for (ct = 0; ct < SIZE; ct++)
{
char choice;
cout << "Enter the employee category: \n"
<< "g: Gunslinger p: PokerPlayer "
<< "b: BadDude q: quit\n";
cin >> choice;
while (strchr("gpbq", choice) == NULL)
{
cout << "Please enter a g, p, b, or q: ";
cin >> choice;
}
if ('q' == choice)
break;
switch (choice)
{
case 'g':
person[ct] = new Gunslinger("Guns", "Linger", 1.2, 3);
break;
case 'p':
person[ct] = new PokerPlayer("Poker", "Player", 2);
break;
case 'b':
person[ct] = new BadDude("Bad", "Dude", 2.1, 5);
break;
}
cin.get();
}
cout << "\nHere is your staff:\n";
for (int i = 0; i < ct; i++)
{
cout << endl;
person[i]->Show();
}
for (int i = 0; i < ct; i++)
delete person[i];
BadDude *badd = new BadDude("Bad", "Dude", 3.3, 12);
cout << "Draw time: " << badd->Gdraw() << endl;
cout << "Next card: " << badd->Cdraw() << endl;
delete badd;
cout << "Bye.\n";
return 0;
}
运行结果:
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.4>g++ person.cpp main.cpp -o main
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.4>main
Enter the employee category:
g: Gunslinger p: PokerPlayer b: BadDude q: quit
g
Enter the employee category:
g: Gunslinger p: PokerPlayer b: BadDude q: quit
p
Enter the employee category:
g: Gunslinger p: PokerPlayer b: BadDude q: quit
b
Enter the employee category:
g: Gunslinger p: PokerPlayer b: BadDude q: quit
q
Here is your staff:
Category: Gunslinger
First name: Guns
Last name: Linger
Time:
Num of scotch:
Category: PokerPlayer
First name: Poker
Last name: Player
Card: 2
First name: Bad
Last name: Dude
Time:
Num of scotch:
Card: 1
Draw time: 16
Next card: 1
Bye.
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.4>
下面是一些类声明:
//emp.h
#include
#include
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, const 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();
};
class manager : virtual public abstr_emp
{
private:
int inchargeof;
protected:
void Data() const;
void Get();
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();
};
class fink : virtual public abstr_emp
{
private:
std::string reportsto;
protected:
void Data() const;
void Get();
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
{
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方法的代码(例如,如果HightFink::showAll()只是调用Fink::showAll()和Manager::showAll(),则它将调用abstr_emp::ShowAll()两次)。提供类方法的实现,并在一个程序中对这些类进行测试。下面是一个小型测试程序:
//main.cpp
#include
#include "emp.h"
using namespace std;
int main(void)
{
employee em("Trip", "Harris", "Thumper");
cout << em << endl;
em.ShowAll();
manager ma("Amorphia", "Spindragib", "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;
}
代码:
//emp.cpp
#include
#include
#include "emp.h"
using std::cin;
using std::cout;
using std::endl;
abstr_emp::~abstr_emp() {}
abstr_emp::abstr_emp()
{
fname = "Null";
lname = "Null";
job = "Null";
}
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 << "Fullname: " << fname << endl;
cout << "Lastname: " << lname << endl;
cout << "Job: " << job << endl;
}
void abstr_emp::SetAll()
{
cout << "Enter firstname: ";
cin >> fname;
cout << "Enter lastname: ";
cin >> lname;
cout << "Ente job: ";
cin.get();
getline(cin, job);
}
std::ostream &operator<<(std::ostream &os, const abstr_emp &e)
{
cout << e.fname << " " << e.lname << " " << e.job << endl;
return os; // TODO: 在此处插入 return 语句
}
employee::employee() : abstr_emp()
{
}
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();
}
void manager::Data() const
{
cout << "Inchargeof: " << inchargeof << endl;
}
void manager::Get()
{
cout << "Enter Inchargeof: ";
cin >> inchargeof;
}
manager::manager() : abstr_emp()
{
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(0)
{
}
manager::manager(const manager &m) : abstr_emp(m)
{
inchargeof = m.inchargeof;
}
void manager::ShowAll() const
{
abstr_emp::ShowAll();
cout << "Inchargeof: " << inchargeof << endl;
}
void manager::SetAll()
{
abstr_emp::SetAll();
cout << "Enter inchargeof: ";
cin >> inchargeof;
}
void fink::Data() const
{
cout << "Reports to: " << reportsto << endl;
}
void fink::Get()
{
cout << "Enter resportsto: ";
cin.get();
getline(cin, reportsto);
}
fink::fink() : abstr_emp()
{
reportsto = "Null";
}
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 &e) : abstr_emp(e)
{
reportsto = e.reportsto;
}
void fink::ShowAll() const
{
abstr_emp::ShowAll();
cout << "Reports to: " << reportsto << endl;
}
void fink::SetAll()
{
abstr_emp::SetAll();
cout << "Enter reports to: ";
cin.get();
getline(cin, reportsto);
}
highfink::highfink() : abstr_emp(), manager(), fink()
{
}
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), manager(f, ico), fink(f)
{
}
highfink::highfink(const manager &m, const std::string &rpo) : abstr_emp(m), manager(m), fink(m, rpo)
{
}
highfink::highfink(const highfink &h) : abstr_emp(h), manager(h), fink(h)
{
}
void highfink::ShowAll() const
{
abstr_emp::ShowAll();
manager::Data();
fink::Data();
}
void highfink::SetAll()
{
abstr_emp::SetAll();
manager::Get();
fink::Get();
}
运行结果:
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.5>g++ emp.cpp main.cpp -o main
C:\Users\81228\Documents\Program\VScode C++ Program\chapter14\14.5>main
Trip Harris Thumper
Fullname: Trip
Lastname: Harris
Job: Thumper
Amorphia Spindragib Nuancer
Fullname: Amorphia
Lastname: Spindragib
Job: Nuancer
Inchargeof: 5
Matt Oggs Oiler
Fullname: Matt
Lastname: Oggs
Job: Oiler
Reports to: Juno Barr
Fullname: Amorphia
Lastname: Spindragib
Job: Nuancer
Inchargeof: 5
Reportsto: Curly Kew
Press a key for next phase:
Enter firstname: Xi
Enter lastname: ye
Ente job: engineer
Enter Inchargeof: 1
Enter resportsto: Null
Using an abstr_emp * pointer:
Fullname: Trip
Lastname: Harris
Job: Thumper
Fullname: Matt
Lastname: Oggs
Job: Oiler
Reports to: Juno Barr
Fullname: Amorphia
Lastname: Spindragib
Job: Nuancer
Inchargeof: 5
Reportsto: Curly Kew
Fullname: Xi
Lastname: ye
Job: engineer
Inchargeof: 1
Reportsto: Null
为什么没有定义赋值运算符?
类中不存在指针成员,不需要深拷贝,使用默认的赋值操作即可。
为什么要将ShowAll()和SetAll()定义为虚的?
因为派生类将修改基类中setAll()与ShowAll()两个函数的行为。
为什么要将abstr_emp定义为虚基类?
虚基类使得highfink从manager和fink继承过来,只包含一个abstr_emp对象的拷贝,节省空间并避免不必要的冲突。
为什么highfink类没有数据部分?
highfink类需要的的数据成员已经包含在了它的父类中。
为什么只需要一个operator<<()版本?
因为这里只显示基类中的三个成员,派生类基类中的基类部分将自动调用基类的友元函数。
如果使用下面的代码替换程序的结尾部分,将会发生什么情况?
abstr_emp str[4] = {em, fi, hf, hf2};
for(int i = 0; i < 4; ++i)
tr[i].showAll()
编译失败,抽象类不能实例化。可以通过将virtual ~abstr_emp() = 0改为virtual ~abstr_emp();,即将abstr_emp变成非抽象类,可编译通过,此时em, fi, hf, hf2这四个派生类对象将被强制转化为基类,所以只调用基类的ShowAll()函数。