习题选自:C Primer Plus(第六版) 内容仅供参考,如有错误,欢迎指正 ! 第十四章- 代码重用笔记
复习题
1. 以A栏的类为基类时,B栏的类采用公有派生还是私有派生更合适
A | B |
---|---|
class Bearclass Kitchenclass Person class Personclass Person, class Automobile | class PolarBearclass Homeclass Programmerclass HorseAndJockeyclass Driver |
A | B | 公有派生还是私有派生合适 |
---|---|---|
class Bear | class PolarBear | 公有派生,因为北极熊也是一种熊,is-a的关系 |
class Kitchen | class Home | 私有派生,因为家中有厨房,has-a的关系 |
class Person | class Programmer | 公有派生,因为程序员也是人,is-a的关系 |
class Person | class HorseAndJockey | 私有派生,因为马和驯马师的组合包人,has-a的关系 |
class Person, class Automobile | class Driver | 人是公有的,人与司机是is-a关系;车是私有的,车与司机是has-a的关系 |
2. 假设有下面的定义:
代码语言:javascript复制class Frabjous {
private:
char fab[20];
public:
Frabjous(const char * s = "C ") : fab(s) { }
virtual void tell() { cout << fab; }
};
class Gloam {
private:
int glip;
Frabjous fb;
public:
Gloam(int g = 0, const char * s = "C ");
Gloam(int g, const Frabjous & f);
void tell();
};
假设Gloam
版本的tell()
应显示glip
和fb
的值,请为这3个Gloam
方法提供定义。
Gloam::Gloam(int g, const char* s) : glip(g), fb(s){}
Gloam::Gloam(int g, const Frabjous &f) : glip(g), fb(f){} //使用Frabjous的默认复制构造函数
void Golam::tell()
{
fb.tell();
cout << glip <<endl;
}
3. 假设有下面的定义:
代码语言:javascript复制class Frabjous {
private:
char fab[20];
public:
Frabjous(const char * s = "C ") : fab(s) { }
virtual void tell() { cout << fab; }
};
class Gloam : private Frabjous{
private:
int glip;
public:
Gloam(int g = 0, const char * s = "C ");
Gloam(int g, const Frabjous & f);
void tell();
};
假设Gloam
版本的tell()
应显示glip
和fab
的值,请为这3个Gloam
方法提供定义。
Gloam::Gloam(int g, const char* s) : glip(g), Frabjous(s){}
Gloam::Gloam(int g, const Frabjous &f) : glip(g), Frabjous(f){} //使用Frabjous的默认复制构造函数
void Golam::tell()
{
Frabjous::tell();
cout << glip <<endl;
}
4. 假设有下面的定义,它是基于程序清单14.13中的Stack
模板和程序清单14.10中的Woker
类的:
Stack<Worker *> sw;
请写出将生成的类声明。只实现类声明,不实现非内联类方法。
代码语言:javascript复制class Stack<Worker *>
{
private:
enum {MAX = 10}; // constant specific to class
Worker * items[MAX]; // holds stack items
int top; // index for top stack item
public:
Stack();
Boolean isempty();
Boolean isfull();
Boolean push(const Worker * & item); // add item to stack
Boolean pop(Worker * & item); // pop top into item
}
5. 使用本章中的模板定义对下面的内容进行定义:
string
对象数组;double
数组栈;- 指向`Worker`对象的指针的栈数组。
程序清单14.18生成了多少个模板类定义?
代码语言:javascript复制ArrayTP<string> str_arr;//string对象数组
StackTP<ArrayTP<double> db_arr_stack;//double数组栈
ArrayTP<StackTP<Worker *>> wkptr_ stack_arr;//指向Worker对象的指针的栈数组
程序清单14.18生成4个模板:ArrayTP<int, 10>
、ArrayTP<double,10>、ArrayTP<int, 5>
和Array<ArrayTP <int, 5>, 10>
。
6. 指出虚基类与非虚基类之间的区别。
如果两条继承路线有相同的祖先,非虚基类会导致最终的派生类中包含祖先成员的两份拷贝,虚基类可以解决这种问题。
编程练习
1.Wine
类有一个string
类对象成员(参见第4章)和一个Pair
对象(参见本章);其中前者用于存储葡萄酒的名称,而后者有2个valarray<int>
对象(参见本章),这两个valarray<int>
对象分别保存了葡萄酒的酿造年份和该年生产的瓶数。例如,Pair
的第1个valarray<int>
对象可能为1988、1992和1996年,第2个valarray<int>
对象可能为24、48和144瓶。Wine
最好有1个int
成员用于存储年数。另外,一些typedef
可能有助于简化编程工作:
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;
这样,PairArray
表示Pair<std::valarray<int>,std::valarray<int>>
。使用包含来实现Wine
类,并用一个简单的程序对其进行测试。Wine类应该有一个默认构造函数以及如下构造函数:
// initialize label to l, number of years to y,
// vintage years to yr[], bottles to bot[]
Wine(const char * l, int y, const int yr[], const int bot[]);
// initialize label to l, number of years to y,
// create array objects of length y
Wine(const char * l, int y);
Wine
类应该有一个GetBottles()
方法,它根据Wine
对象能够存储几种年份(y),提示用户输入年份和瓶数。方法Label()
返回一个指向葡萄酒名称的引用。sum()
方法返回Pair对象中第二个valarray<int>
对象中的瓶数总和。测试程序应提示用户输入葡萄酒名称、元素个数以及每个元素存储的年份和瓶数等信息。程序将使用这些数据来构造一个Wine对象,然后显示对象中保存的信息。
下面是一个简单的测试程序:
代码语言:javascript复制// pe14-1.cpp -- using Wine class with containment
#include <iostream>
#include "winec.h"
int main ( void )
{
using std::cin;
using std::cout;
using std::endl;
cout << "Enter name of wine: ";
char lab[50];
cin.getline(lab, 50);
cout << "Enter number of years: ";
int yrs;
cin >> yrs;
Wine holding(lab, yrs); // store label, years, give arrays yrs elements
holding.GetBottles(); // solicit input for year, bottle count
holding.Show(); // display object contents
const int YRS = 3;
int y[YRS] = {1993, 1995, 1998};
int b[YRS] = { 48, 60, 72};
// create new object, initialize using data in arrays y and b
Wine more("Gushing Grape Red",YRS, y, b);
more.Show();
cout << "Total bottles for " << more.Label() // use Label() method
<< ": " << more.sum() << endl; // use sum() method
cout << "Byen";
return 0;
}
下面是该程序的运行情况:
代码语言:javascript复制Enter name of wine: Gully Wash
Enter number of years: 4
Enter Gully Wash data for 4 year(s):
Enter year: 1988
Enter bottles for that year: 42
Enter year: 1994
Enter bottles for that year: 58
Enter year: 1998
Enter bottles for that year: 122
Enter year: 2001
Enter bottles for that year: 144
Wine: Gully Wash
Year Bottles
1988 42
1994 58
1998 122
2001 144
Wine: Gushing Grape Red
Year Bottles
1993 48
1995 60
1998 72
Total bottles for Gushing Grape Red: 180
Bye
pair.cpp:
代码语言:javascript复制#ifndef PAIR_H_
#define PAIR_H_
template <typename T1, typename T2>
class Pair {
private:
T1 t1;
T2 t2;
public:
Pair(const T1& t1, const T2& t2) : t1(t1), t2(t2) {}
Pair(const Pair<T1, T2>& p);
T1& first();
T2& second();
T1 first() const { return t1; }
T2 second() const { return t2; }
};
template <typename T1, typename T2>
Pair<T1, T2>::Pair(const Pair<T1, T2>& p) {
t1 = p.t1;
t2 = p.t2;
}
template <typename T1, typename T2>
T1& Pair<T1, T2>::first() {
return t1;
}
template <typename T1, typename T2>
T2& Pair<T1, T2>::second() {
return t2;
}
#endif // PAIR_H_
winec.h:
代码语言:javascript复制#ifndef WINEC_H_
#define WINEC_H_
#include <iostream>
#include <string>
#include <valarray>
#include "pair.h"
class Wine {
private:
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;
std::string label;
PairArray data;
int years_num;
public:
Wine(const char* l, int y, const int yr[], const int bot[]);
Wine(const char* l, int y);
void GetBottles();
const std::string& Label() const { return label; }
int sum() const;
void Show() const;
};
#endif // WINEC_H_
winec.cpp:
代码语言:javascript复制#include "winec.h"
Wine::Wine(const char* l, int y, const int yr[], const int bot[])
: label(l), years_num(y), data(ArrayInt(yr, y), ArrayInt(bot, y)) {}
Wine::Wine(const char* l, int y)
: label(l), years_num(y), data(ArrayInt(y), ArrayInt(y)) {}
void Wine::GetBottles() {
int yn = 0;
int b = 0;
std::cout << "Enter " << label << " data for " << years_num << " year(s)"
<< std::endl;
for (int i = 0; i < years_num; i) {
std::cout << "Enter year: ";
std::cin >> yn;
data.first()[i] = yn;
std::cout << "Enter bottles for that year: ";
std::cin >> b;
data.second()[i] = b;
}
}
int Wine::sum() const { return data.second().sum(); }
void Wine::Show() const {
std::cout << "Wine: " << label << std::endl;
std::cout << "Year "
<< " Bottles" << std::endl;
for (int i = 0; i < years_num; i) {
std::cout << data.second()[i] << " " << data.first()[i] << std::endl;
}
}
2. 采用私有继承而不是包含来完成编程练习1。同样,一些typedef可能会有所帮助,另外,您可能还需要考虑诸如下面这样的语句的含义:
代码语言:javascript复制PairArray::operator=(PairArray(ArrayInt(),ArrayInt()));
cout << (const string &)(*this);
您设计的类应该可以使用编程练习1中的测试程序进行测试。
pair.cpp:
代码语言:javascript复制#ifndef PAIR_H_
#define PAIR_H_
template <typename T1, typename T2>
class Pair {
private:
T1 t1;
T2 t2;
public:
Pair(const T1& t1, const T2& t2) : t1(t1), t2(t2) {}
Pair(const Pair<T1, T2>& p);
T1& first();
T2& second();
T1 first() const { return t1; }
T2 second() const { return t2; }
};
template <typename T1, typename T2>
Pair<T1, T2>::Pair(const Pair<T1, T2>& p) {
t1 = p.t1;
t2 = p.t2;
}
template <typename T1, typename T2>
T1& Pair<T1, T2>::first() {
return t1;
}
template <typename T1, typename T2>
T2& Pair<T1, T2>::second() {
return t2;
}
#endif // PAIR_H_
winec.h:
代码语言:javascript复制#ifndef WINEC_H_
#define WINEC_H_
#include <iostream>
#include <string>
#include <valarray>
#include "pair.h"
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;
class Wine : private std::string, private PairArray {
private:
int years_num;
public:
Wine(const char* l, int y, const int yr[], const int bot[]);
Wine(const char* l, int y);
void GetBottles();
const std::string& Label() const { return (std::string&)(*this); }
int sum() const { return PairArray::second().sum(); }
void Show() const;
};
#endif // WINEC_H_
winec.cpp:
代码语言:javascript复制#include "winec.h"
Wine::Wine(const char* l, int y, const int yr[], const int bot[])
: std::string(l),
years_num(y),
PairArray(ArrayInt(yr, y), ArrayInt(bot, y)) {}
Wine::Wine(const char* l, int y)
: std::string(l), years_num(y), PairArray(ArrayInt(y), ArrayInt(y)) {}
void Wine::GetBottles() {
int yn = 0;
int b = 0;
std::cout << "Enter " << Label() << " data for " << years_num << " year(s)"
<< std::endl;
for (int i = 0; i < years_num; i) {
std::cout << "Enter year: ";
std::cin >> yn;
PairArray::first()[i] = yn;
std::cout << "Enter bottles for that year: ";
std::cin >> b;
PairArray::second()[i] = b;
}
}
void Wine::Show() const {
std::cout << "Wine: " << Label() << std::endl;
std::cout << "Year "
<< " Bottles" << std::endl;
for (int i = 0; i < years_num; i) {
std::cout << PairArray::second()[i] << " " << PairArray::first()[i]
<< std::endl;
}
}
3. 定义一个QueueTp
模板。然后在一个类似于程序清单14.12的程序中创建一个指向Worker
的指针队列(参见程序清单14.10中的定义),并使用该队列来测试它。
worker.h:
代码语言:javascript复制#ifndef WORKER_H_
#define WORKER_H_
#include <string>
class Worker // an abstract base class
{
private:
std::string fullname;
long id;
public:
Worker() : fullname("none"), id(0L) {}
Worker(const std::string& s, long n) : fullname(s), id(n) {}
virtual ~Worker() {}
virtual void Set();
virtual void Show() const;
};
#endif // WORKER_H_
worker.cpp:
代码语言:javascript复制#include "worker.h"
#include <iostream>
void Worker::Set() {
std::cout << "Enter worker's name: ";
getline(std::cin, fullname);
std::cout << "Enter worker's ID: ";
std::cin >> id;
while (std::cin.get() != 'n') continue;
}
void Worker::Show() const {
std::cout << "Name: " << fullname << "n";
std::cout << "Employee ID: " << id << "n";
}
queueTp.h:
代码语言:javascript复制#ifndef QUEUETP_H_
#define QUEUETP_H_
template <typename T>
class QueueTp {
private:
enum { Q_SIZE = 10 };
struct Node {
T item;
Node* next_ptr;
};
Node* front;
Node* rear;
int items;
const int qsize;
public:
QueueTp(int qs = Q_SIZE);
~QueueTp();
bool isempty() const { return items == 0; }
bool isfull() const { return items == qsize; }
int queuecount() const { return items; }
bool push(const T& item);
bool pop(T& item);
};
template <typename T>
QueueTp<T>::QueueTp(int qs) : qsize(qs) {
front = rear = nullptr;
items = 0;
}
template <typename T>
QueueTp<T>::~QueueTp() {
Node* temp;
while (front != nullptr) {
temp = front;
front = front->next_ptr;
delete temp;
}
}
template <typename T>
bool QueueTp<T>::push(const T& item) {
if (isfull()) return false;
Node* add = new Node;
if (front == nullptr) // if queue is empty
{
add->item = item;
add->next_ptr = nullptr;
front = rear = add;
} else {
add->item = item;
add->next_ptr = nullptr;
rear->next_ptr = add;
rear = add;
}
items ;
return true;
}
template <typename T>
bool QueueTp<T>::pop(T& item) {
if (isempty()) return false;
item = front->item;
Node* temp;
temp = front;
front = front->next_ptr;
delete temp;
items--;
return true;
}
#endif // QUEUETP_H_
main.cpp:
代码语言:javascript复制#include <cstring>
#include <iostream>
#include "queueTp.h"
#include "worker.h"
int main() {
using std::cin;
using std::cout;
using std::endl;
using std::strchr;
QueueTp<Worker> q(3);
int count = 0;
Worker* pWorker = new Worker[3];
pWorker[0] = Worker("Jack", 000001);
pWorker[1] = Worker("Toou", 000002);
pWorker[2] = Worker("Boub", 000003);
while (q.queuecount() < 3) {
pWorker[count].Show();
q.push(pWorker[count ]);
}
if (q.queuecount() == 3)
std::cout << "The Queue is full, the elements are: n";
while (q.queuecount() > 0) {
pWorker[--count].Show();
q.pop(pWorker[count]);
}
if (q.queuecount() == 0) std::cout << "The Queue is empty now. n";
delete[] pWorker;
return 0;
}
4. Person
类保存人的名和姓。除构造函数外,它还有Show()
方法,用于显示名和姓。Gunslinger
类以Person
类为虚基类派生而来,它包含一个Draw()
成员,该方法返回一个double
值,表示枪手的拔枪时间。这个类还包含一个int
成员,表示枪手枪上的刻痕数。最后,这个类还包含一个Show()
函数,用于显示所有这些信息。PokerPlayer
类以Person
类为虚基类派生而来。它包含一个Draw()
成员,该函数返回一个1~52的随机数,用于表示扑克牌的值(也可以定义一个Card类,其中包含花色和面值成员,然后让Draw()
返回一个Card对象)。PokerPlayer
类使用Person
类的show()
函数。BadDude()
类从Gunslinger
和PokerPlayer
类公有派生而来。它包含Gdraw()
成员(返回坏蛋拔枪的时间)和Cdraw()
成员(返回下一张扑克牌),另外还有一个合适的Show()
函数。请定义这些类和方法以及其他必要的方法(如用于设置对象值的方法),并使用一个类似于程序清单14.12的简单程序对它们进行测试。
person.h:
代码语言:javascript复制#ifndef PERSON_H_
#define PERSON_H_
#include <string>
class Person {
private:
std::string firstname;
std::string lastname;
protected:
virtual void Data() const;
public:
Person(const char* fn = "none", const char* ln = "none")
: firstname(fn), lastname(ln) {}
// no explicit copy constructor function
virtual ~Person() {}
virtual void Show() const;
virtual void Set();
};
#endif // PERSON_H_
person.cpp:
代码语言:javascript复制#include "person.h"
#include <iostream>
void Person::Data() const {
std::cout << firstname << ", " << lastname << std::endl;
}
void Person::Show() const { Data(); }
void Person::Set() {
std::cout << "Enter firstname: ";
std::cin >> firstname;
std::cout << "Enter lastname: ";
std::cin >> lastname;
}
pokerplayer.h:
代码语言:javascript复制#ifndef POKERPLAYER_H_
#define POKERPLAYER_H_
#include "person.h"
class PokerPlayer : virtual public Person {
public:
PokerPlayer(const char* fn = "none", const char* ln = "none")
: Person(fn, ln) {}
int Draw() const;
};
#endif // POKERPLAYER_H_
pokerplayer.cpp:
代码语言:javascript复制#include "pokerplayer.h"
#include <cstdlib>
#include <ctime>
int PokerPlayer::Draw() const {
srand(time(0));
return int(rand()) % 52 1;
}
gunslinger.h:
代码语言:javascript复制#ifndef GUNSLINGER_H_
#define GUNSLINGER_H_
#include "person.h"
class Gunslinger : virtual public Person {
private:
double drawtime;
int notches;
protected:
void Data() const;
public:
Gunslinger(const char* fn = "none", const char* ln = "none", double d = 0.0,
int n = 0)
: Person(fn, ln), drawtime(d), notches(n) {}
double Draw() const { return drawtime; }
double Notches() const { return notches; }
void Show() const;
void Set();
};
#endif // GUNSLINGER_H_
gunslinger.cpp:
代码语言:javascript复制#include "gunslinger.h"
#include <iostream>
void Gunslinger::Data() const {
std::cout << "Draw: " << drawtime << std::endl;
std::cout << "Notches: " << notches << std::endl;
}
void Gunslinger::Show() const {
Person::Data();
Data();
}
void Gunslinger::Set() {
Person::Set();
std::cout << "Enter Drawtime: ";
std::cin >> drawtime;
std::cout << "Enter Notches: ";
std::cin >> notches;
}
baddude.h:
代码语言:javascript复制#ifndef BADDUDE_H_
#define BADDUDE_H_
#include "gunslinger.h"
#include "pokerplayer.h"
class BadDude : public PokerPlayer, public Gunslinger {
protected:
void Data() const;
public:
double Gdraw() const { return Gunslinger::Draw(); }
double Cdraw() const { return PokerPlayer::Draw(); }
void Show() const;
void Set();
};
#endif // BADDUDE_H_
baddude.cpp:
代码语言:javascript复制#include "baddude.h"
void BadDude::Data() const {
Gunslinger::Data();
PokerPlayer::Data();
}
void BadDude::Show() const { Data(); }
void BadDude::Set() { Gunslinger::Set(); }
main.cpp:
代码语言:javascript复制#include <cstring>
#include <iostream>
#include "baddude.h"
#include "gunslinger.h"
#include "person.h"
#include "pokerplayer.h"
const int SIZE = 5;
int main() {
using namespace std;
int ct, i;
Person* gang[SIZE];
for (ct = 0; ct < SIZE; ct ) {
char choice;
cout << "Enter the gang category: n"
<< "o: ordinary person g: gunslinger "
<< "p: pokerplayer b: bad dude q: quit n";
cin >> choice;
while (strchr("ogpbq", choice) == NULL) {
cout << "Please enter an o, g, p, b, or q: ";
cin >> choice;
}
if (choice == 'q') break;
switch (choice) {
case 'o':
gang[ct] = new Person;
break;
case 'g':
gang[ct] = new Gunslinger;
break;
case 'p':
gang[ct] = new PokerPlayer;
break;
case 'b':
gang[ct] = new BadDude;
break;
}
cin.get();
gang[ct]->Set();
}
cout << "nHere is your gang: n";
for (i = 0; i < ct; i ) {
cout << endl;
gang[i]->Show();
}
for (i = 0; i < ct; i ) delete gang[i];
cout << "Bye" << endl;
return 0;
}
5. 下面是一些类声明:
代码语言:javascript复制// emp.h -- header file for abstr_emp class and children
#include <iostream>
#include <string>
class abstr_emp
{
private:
std::string fname; // abstr_emp's first name
std::string lname; // abstr_emp's last name
std::string job;
public:
abstr_emp();
abstr_emp(const std::string & fn, const std::string & ln,
const std::string & j);
virtual void ShowAll() const; // labels and shows all data
virtual void SetAll(); // prompts user for values
friend std::ostream &
operator<<(std::ostream & os, const abstr_emp & e);
// just displays first and last name
virtual ~abstr_emp() = 0; // virtual base class
};
class employee : public abstr_emp
{
public:
employee();
employee(const std::string & fn, const std::string & ln,
const std::string & j);
virtual void ShowAll() const;
virtual void SetAll();
};
class manager: virtual public abstr_emp
{
private:
int inchargeof; // number of abstr_emps managed
protected:
int InChargeOf() const { return inchargeof; } // output
int & InChargeOf(){ return inchargeof; } // input
public:
manager();
manager(const std::string & fn, const std::string & ln,
const std::string & j, int ico = 0);
manager(const abstr_emp & e, int ico);
manager(const manager & m);
virtual void ShowAll() const;
virtual void SetAll();
};
class fink: virtual public abstr_emp
{
private:
std::string reportsto; // to whom fink reports
protected:
const std::string ReportsTo() const { return reportsto; }
std::string & ReportsTo(){ return reportsto; }
public:
fink();
fink(const std::string & fn, const std::string & ln,
const std::string & j, const std::string & rpo);
fink(const abstr_emp & e, const std::string & rpo);
fink(const fink & e);
virtual void ShowAll() const;
virtual void SetAll();
};
class highfink: public manager, public fink // management fink
{
public:
highfink();
highfink(const std::string & fn, const std::string & ln,
const std::string & j, const std::string & rpo,
int ico);
highfink(const abstr_emp & e, const std::string & rpo, int ico);
highfink(const fink & f, int ico);
highfink(const manager & m, const std::string & rpo);
highfink(const highfink & h);
virtual void ShowAll() const;
virtual void SetAll();
};
注意,该类层次结构使用了带虚基类的MI,所以要牢记这种情况下用于构造函数初始化列表的特殊规则。还需要注意的是,有些方法被声明为保护的。这可以简化一些highfink
方法的代码(例如,如果highfink::ShowAll()
只是调用fink::ShowAll()
和manager::ShwAll()
,则它将调用abstr_emp::ShowAll()
两次)。请提供类方法的实现,并在一个程序中对这些类进行测试。下面是一个小型测试程序:
// pe14-5.cpp
// useemp1.cpp -- using the abstr_emp classes
#include <iostream>
using namespace std;
#include "emp.h"
int main(void)
{
employee em("Trip", "Harris", "Thumper");
cout << em << endl;
em.ShowAll();
manager ma("Amorphia", "Spindragon", "Nuancer", 5);
cout << ma << endl;
ma.ShowAll();
fink fi("Matt", "Oggs", "Oiler", "Juno Barr");
cout << fi << endl;
fi.ShowAll();
highfink hf(ma, "Curly Kew"); // recruitment?
hf.ShowAll();
cout << "Press a key for next phase:n";
cin.get();
highfink hf2;
hf2.SetAll();
cout << "Using an abstr_emp * pointer:n";
abstr_emp * tri[4] = {&em, &fi, &hf, &hf2};
for (int i = 0; i < 4; i )
tri[i]->ShowAll();
return 0;
}
类方法的实现:emp.cpp:
代码语言:javascript复制#include "emp.h"
/********abstr_emp**********/
abstr_emp::abstr_emp() {
fname = "none";
lname = "none";
job = "none";
}
abstr_emp::abstr_emp(const std::string& fn, const std::string& ln,
const std::string& j)
: fname(fn), lname(ln), job(j) {}
abstr_emp::~abstr_emp() {}
void abstr_emp::ShowAll() const {
std::cout << "firstname: " << fname << std::endl;
std::cout << "lastname: " << lname << std::endl;
std::cout << "job: " << job << std::endl;
}
void abstr_emp::SetAll() {
std::cout << "Enter firstname: ";
std::getline(std::cin, fname);
std::cout << "Enter lastname: ";
std::getline(std::cin, lname);
std::cout << "Enter job: ";
std::getline(std::cin, job);
}
std::ostream& operator<<(std::ostream& os, const abstr_emp& e) {
os << e.lname << " " << e.fname << ", " << e.job;
return os;
}
/********employee**********/
employee::employee() {}
employee::employee(const std::string& fn, const std::string& ln,
const std::string& j)
: abstr_emp(fn, ln, j) {}
void employee::ShowAll() const { abstr_emp::ShowAll(); }
void employee::SetAll() { abstr_emp::SetAll(); }
/********manager**********/
manager::manager() { inchargeof = 0; }
manager::manager(const std::string& fn, const std::string& ln,
const std::string& j, int ico)
: abstr_emp(fn, ln, j), inchargeof(ico) {}
manager::manager(const abstr_emp& e, int ico) : abstr_emp(e) {
inchargeof = ico;
}
manager::manager(const manager& m) : abstr_emp(m) { inchargeof = m.inchargeof; }
void manager::ShowAll() const {
abstr_emp::ShowAll();
std::cout << "Inchargeof: " << inchargeof << std::endl;
}
void manager::SetAll() {
abstr_emp::SetAll();
std::cout << "Enter inchargeof: ";
std::cin >> inchargeof;
std::cin.get();
}
/********fink**********/
fink::fink() { reportsto = "none"; }
fink::fink(const std::string& fn, const std::string& ln, const std::string& j,
const std::string& rpo)
: abstr_emp(fn, ln, j), reportsto(rpo) {}
fink::fink(const abstr_emp& e, const std::string& rpo)
: abstr_emp(e), reportsto(rpo) {}
fink::fink(const fink& f) : abstr_emp(f) { reportsto = f.reportsto; }
void fink::ShowAll() const {
abstr_emp::ShowAll();
std::cout << "Reportsto: " << reportsto << std::endl;
}
void fink::SetAll() {
abstr_emp::SetAll();
std::cout << "Enter reportsto: ";
std::getline(std::cin, reportsto);
}
/********highfink**********/
highfink::highfink() {}
highfink::highfink(const std::string& fn, const std::string& ln,
const std::string& j, const std::string& rpo, int ico)
: abstr_emp(fn, ln, j), manager(fn, ln, j, ico), fink(fn, ln, j, rpo) {}
highfink::highfink(const abstr_emp& e, const std::string& rpo, int ico)
: abstr_emp(e), manager(e, ico), fink(e, rpo) {}
highfink::highfink(const fink& f, int ico)
: abstr_emp(f), fink(f), manager((const abstr_emp&)f, ico) {}
highfink::highfink(const manager& m, const std::string& rpo)
: abstr_emp(m), manager(m), fink((const abstr_emp&)m, rpo) {}
highfink::highfink(const highfink& h) : abstr_emp(h), manager(h), fink(h) {}
void highfink::ShowAll() const {
abstr_emp::ShowAll();
std::cout << "Inchargeof: " << manager::InChargeOf() << std::endl;
std::cout << "Reportsto: " << fink::ReportsTo() << std::endl;
}
void highfink::SetAll() {
abstr_emp::SetAll();
std::cout << "Enter reportsto: ";
std::getline(std::cin, fink::ReportsTo());
std::cout << "Enter Inchargeof: ";
std::cin >> manager::InChargeOf();
std::cin.get();
}
为什么没有定义赋值运算符?
类中不存在指针成员,不需要深拷贝,使用默认的赋值操作即可。
为什么要将ShowAll()
和SetAll()
定义为虚的?
因为派生类将修改基类中setAll()
与ShowAll()
两个函数的行为。
为什么要将abstr_emp
定义为虚基类?
虚基类使得highfink
从manager
和fink
继承过来,只包含一个abstr_emp
对象的拷贝,节省空间并避免不必要的冲突。
为什么highfink
类没有数据部分?
highfink
类需要的的数据成员已经包含在了它的父类中。
为什么只需要一个operator<<()
版本?
因为这里只显示基类中的三个成员,派生类基类中的基类部分将自动调用基类的友元函数。
如果使用下面的代码替换程序的结尾部分,将会发生什么情况?
代码语言:javascript复制abstr_emp tri[4] = {em, fi, hf, hf2};
for (int i = 0; i < 4; i )
tri[i].ShowAll();
编译失败,抽象类不能实例化。可以通过将virtua ~abstr_emp() = 0
改为virtual ~abstr_emp();
,即将abstr_emp
变成非抽象类,可编译通过,此时em
, fi
, hf
, hf2
这四个派生类对象将被强制转化为基类,所以只调用基类的ShowAll()
函数。