习题选自:C++ Primer Plus(第六版)
内容仅供参考,如有错误,欢迎指正 !

第十四章- 代码重用笔记

复习题

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

A B
class Bear
class Kitchen
class Person
class Person
class Person, class Automobile
class PolarBear
class Home
class Programmer
class HorseAndJockey
class 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. 假设有下面的定义:

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

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

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

3. 假设有下面的定义:

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

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

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

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

Stack<Worker *> sw;

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

class Stack<Worker *>
{private:enum {MAX = 10}; // constant specific to classWorker * items[MAX]; // holds stack itemsint top; // index for top stack itempublic:Stack();Boolean isempty();Boolean isfull();Boolean push(const Worker * & item); // add item to stackBoolean pop(Worker * & item); // pop top into item
}

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

  • string对象数组;

  • double数组栈;

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

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

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

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

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

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

编程练习

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

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

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

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

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

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

// pe14-1.cpp -- using Wine class with containment
#include <iostream>
#include "winec.h"
int main ( void )
{using std::cin;using std::cout;using std::endl;cout << "Enter name of wine: ";char lab[50];cin.getline(lab, 50);cout << "Enter number of years: ";int yrs;cin >> yrs;Wine holding(lab, yrs); // store label, years, give arrays yrs elementsholding.GetBottles(); // solicit input for year, bottle countholding.Show(); // display object contentsconst 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 bWine more("Gushing Grape Red",YRS, y, b);more.Show();cout << "Total bottles for " << more.Label() // use Label() method<< ": " << more.sum() << endl; // use sum() methodcout << "Bye\n";return 0;
}

下面是该程序的运行情况

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

pair.cpp:

#ifndef PAIR_H_
#define PAIR_H_template <typename T1, typename T2>
class Pair {private:T1 t1;T2 t2;public:Pair(const T1& t1, const T2& t2) : t1(t1), t2(t2) {}Pair(const Pair<T1, T2>& p);T1& first();T2& second();T1 first() const { return t1; }T2 second() const { return t2; }
};template <typename T1, typename T2>
Pair<T1, T2>::Pair(const Pair<T1, T2>& p) {t1 = p.t1;t2 = p.t2;
}template <typename T1, typename T2>
T1& Pair<T1, T2>::first() {return t1;
}template <typename T1, typename T2>
T2& Pair<T1, T2>::second() {return t2;
}#endif  // PAIR_H_

winec.h:

#ifndef WINEC_H_
#define WINEC_H_#include <iostream>
#include <string>
#include <valarray>#include "pair.h"class Wine {private:typedef std::valarray<int> ArrayInt;typedef Pair<ArrayInt, ArrayInt> PairArray;std::string label;PairArray data;int years_num;public:Wine(const char* l, int y, const int yr[], const int bot[]);Wine(const char* l, int y);void GetBottles();const std::string& Label() const { return label; }int sum() const;void Show() const;
};#endif  // WINEC_H_

winec.cpp:

#include "winec.h"Wine::Wine(const char* l, int y, const int yr[], const int bot[]): label(l), years_num(y), data(ArrayInt(yr, y), ArrayInt(bot, y)) {}Wine::Wine(const char* l, int y): label(l), years_num(y), data(ArrayInt(y), ArrayInt(y)) {}void Wine::GetBottles() {int yn = 0;int b = 0;std::cout << "Enter " << label << " data for " << years_num << " year(s)"<< std::endl;for (int i = 0; i < years_num; ++i) {std::cout << "Enter year: ";std::cin >> yn;data.first()[i] = yn;std::cout << "Enter bottles for that year: ";std::cin >> b;data.second()[i] = b;}
}int Wine::sum() const { return data.second().sum(); }void Wine::Show() const {std::cout << "Wine: " << label << std::endl;std::cout << "Year  "<< "  Bottles" << std::endl;for (int i = 0; i < years_num; ++i) {std::cout << data.second()[i] << "    " << data.first()[i] << std::endl;}
}

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

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

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

pair.cpp:

#ifndef PAIR_H_
#define PAIR_H_template <typename T1, typename T2>
class Pair {private:T1 t1;T2 t2;public:Pair(const T1& t1, const T2& t2) : t1(t1), t2(t2) {}Pair(const Pair<T1, T2>& p);T1& first();T2& second();T1 first() const { return t1; }T2 second() const { return t2; }
};template <typename T1, typename T2>
Pair<T1, T2>::Pair(const Pair<T1, T2>& p) {t1 = p.t1;t2 = p.t2;
}template <typename T1, typename T2>
T1& Pair<T1, T2>::first() {return t1;
}template <typename T1, typename T2>
T2& Pair<T1, T2>::second() {return t2;
}#endif  // PAIR_H_

winec.h:

#ifndef WINEC_H_
#define WINEC_H_#include <iostream>
#include <string>
#include <valarray>#include "pair.h"typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;class Wine : private std::string, private PairArray {private:int years_num;public:Wine(const char* l, int y, const int yr[], const int bot[]);Wine(const char* l, int y);void GetBottles();const std::string& Label() const { return (std::string&)(*this); }int sum() const { return PairArray::second().sum(); }void Show() const;
};#endif  // WINEC_H_

winec.cpp:

#include "winec.h"Wine::Wine(const char* l, int y, const int yr[], const int bot[]): std::string(l),
years_num(y),
PairArray(ArrayInt(yr, y), ArrayInt(bot, y)) {}Wine::Wine(const char* l, int y): std::string(l), years_num(y), PairArray(ArrayInt(y), ArrayInt(y)) {}void Wine::GetBottles() {int yn = 0;int b = 0;std::cout << "Enter " << Label() << " data for " << years_num << " year(s)"<< std::endl;for (int i = 0; i < years_num; ++i) {std::cout << "Enter year: ";std::cin >> yn;PairArray::first()[i] = yn;std::cout << "Enter bottles for that year: ";std::cin >> b;PairArray::second()[i] = b;}
}void Wine::Show() const {std::cout << "Wine: " << Label() << std::endl;std::cout << "Year  "<< "  Bottles" << std::endl;for (int i = 0; i < years_num; ++i) {std::cout << PairArray::second()[i] << "    " << PairArray::first()[i]<< std::endl;}
}

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

worker.h:

#ifndef WORKER_H_
#define WORKER_H_#include <string>class Worker  // an abstract base class
{private:std::string fullname;long id;public:Worker() : fullname("none"), id(0L) {}Worker(const std::string& s, long n) : fullname(s), id(n) {}virtual ~Worker() {}virtual void Set();virtual void Show() const;
};#endif  // WORKER_H_

worker.cpp:

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

queueTp.h:

#ifndef QUEUETP_H_
#define QUEUETP_H_template <typename T>
class QueueTp {private:enum { Q_SIZE = 10 };struct Node {T item;Node* next_ptr;};Node* front;Node* rear;int items;const int qsize;public:QueueTp(int qs = Q_SIZE);~QueueTp();bool isempty() const { return items == 0; }bool isfull() const { return items == qsize; }int queuecount() const { return items; }bool push(const T& item);bool pop(T& item);
};template <typename T>
QueueTp<T>::QueueTp(int qs) : qsize(qs) {front = rear = nullptr;items = 0;
}template <typename T>
QueueTp<T>::~QueueTp() {Node* temp;while (front != nullptr) {temp = front;front = front->next_ptr;delete temp;}
}template <typename T>
bool QueueTp<T>::push(const T& item) {if (isfull()) return false;Node* add = new Node;if (front == nullptr)  // if queue is empty{add->item = item;add->next_ptr = nullptr;front = rear = add;} else {add->item = item;add->next_ptr = nullptr;rear->next_ptr = add;rear = add;}items++;return true;
}template <typename T>
bool QueueTp<T>::pop(T& item) {if (isempty()) return false;item = front->item;Node* temp;temp = front;front = front->next_ptr;delete temp;items--;return true;
}#endif  // QUEUETP_H_

main.cpp:

#include <cstring>
#include <iostream>#include "queueTp.h"
#include "worker.h"int main() {using std::cin;using std::cout;using std::endl;using std::strchr;QueueTp<Worker> q(3);int count = 0;Worker* pWorker = new Worker[3];pWorker[0] = Worker("Jack", 000001);pWorker[1] = Worker("Toou", 000002);pWorker[2] = Worker("Boub", 000003);while (q.queuecount() < 3) {pWorker[count].Show();q.push(pWorker[count++]);}if (q.queuecount() == 3)std::cout << "The Queue is full, the elements are: \n";while (q.queuecount() > 0) {pWorker[--count].Show();q.pop(pWorker[count]);}if (q.queuecount() == 0) std::cout << "The Queue is empty now. \n";delete[] pWorker;return 0;
}

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

person.h:

#ifndef PERSON_H_
#define PERSON_H_#include <string>class Person {private:std::string firstname;std::string lastname;protected:virtual void Data() const;public:Person(const char* fn = "none", const char* ln = "none"): firstname(fn), lastname(ln) {}// no explicit copy constructor functionvirtual ~Person() {}virtual void Show() const;virtual void Set();
};#endif  // PERSON_H_

person.cpp:

#include "person.h"#include <iostream>void Person::Data() const {std::cout << firstname << ", " << lastname << std::endl;
}void Person::Show() const { Data(); }void Person::Set() {std::cout << "Enter firstname: ";std::cin >> firstname;std::cout << "Enter lastname: ";std::cin >> lastname;
}

pokerplayer.h:

#ifndef POKERPLAYER_H_
#define POKERPLAYER_H_#include "person.h"class PokerPlayer : virtual public Person {public:PokerPlayer(const char* fn = "none", const char* ln = "none"): Person(fn, ln) {}int Draw() const;
};#endif  // POKERPLAYER_H_

pokerplayer.cpp:

#include "pokerplayer.h"#include <cstdlib>
#include <ctime>int PokerPlayer::Draw() const {srand(time(0));return int(rand()) % 52 + 1;
}

gunslinger.h:

#ifndef GUNSLINGER_H_
#define GUNSLINGER_H_#include "person.h"class Gunslinger : virtual public Person {private:double drawtime;int notches;protected:void Data() const;public:Gunslinger(const char* fn = "none", const char* ln = "none", double d = 0.0,int n = 0): Person(fn, ln), drawtime(d), notches(n) {}double Draw() const { return drawtime; }double Notches() const { return notches; }void Show() const;void Set();
};#endif  // GUNSLINGER_H_

gunslinger.cpp:

#include "gunslinger.h"#include <iostream>void Gunslinger::Data() const {std::cout << "Draw: " << drawtime << std::endl;std::cout << "Notches: " << notches << std::endl;
}void Gunslinger::Show() const {Person::Data();Data();
}void Gunslinger::Set() {Person::Set();std::cout << "Enter Drawtime: ";std::cin >> drawtime;std::cout << "Enter Notches: ";std::cin >> notches;
}

baddude.h:

#ifndef BADDUDE_H_
#define BADDUDE_H_#include "gunslinger.h"
#include "pokerplayer.h"class BadDude : public PokerPlayer, public Gunslinger {protected:void Data() const;public:double Gdraw() const { return Gunslinger::Draw(); }double Cdraw() const { return PokerPlayer::Draw(); }void Show() const;void Set();
};#endif  // BADDUDE_H_

baddude.cpp:

#include "baddude.h"void BadDude::Data() const {Gunslinger::Data();PokerPlayer::Data();
}void BadDude::Show() const { Data(); }void BadDude::Set() { Gunslinger::Set(); }

main.cpp:

#include <cstring>
#include <iostream>#include "baddude.h"
#include "gunslinger.h"
#include "person.h"
#include "pokerplayer.h"const int SIZE = 5;int main() {using namespace std;int ct, i;Person* gang[SIZE];for (ct = 0; ct < SIZE; ct++) {char choice;cout << "Enter the gang category: \n"<< "o: ordinary person  g: gunslinger  "<< "p: pokerplayer  b: bad dude  q: quit \n";cin >> choice;while (strchr("ogpbq", choice) == NULL) {cout << "Please enter an o, g, p, b, or q: ";cin >> choice;}if (choice == 'q') break;switch (choice) {case 'o':gang[ct] = new Person;break;case 'g':gang[ct] = new Gunslinger;break;case 'p':gang[ct] = new PokerPlayer;break;case 'b':gang[ct] = new BadDude;break;}cin.get();gang[ct]->Set();}cout << "\nHere is your gang: \n";for (i = 0; i < ct; i++) {cout << endl;gang[i]->Show();}for (i = 0; i < ct; i++) delete gang[i];cout << "Bye" << endl;return 0;
}

5. 下面是一些类声明:

// emp.h -- header file for abstr_emp class and children
#include <iostream>
#include <string>
class abstr_emp
{private:std::string fname; // abstr_emp's first namestd::string lname; // abstr_emp's last namestd::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 datavirtual void SetAll(); // prompts user for valuesfriend std::ostream &operator<<(std::ostream & os, const abstr_emp & e);// just displays first and last namevirtual ~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 managedprotected:int InChargeOf() const { return inchargeof; } // outputint & InChargeOf(){ return inchargeof; } // inputpublic: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 reportsprotected:const std::string ReportsTo() const { return reportsto; }std::string & ReportsTo(){ return reportsto; }public:fink();fink(const std::string & fn, const std::string & ln,const std::string & j, const std::string & rpo);fink(const abstr_emp & e, const std::string & rpo);fink(const fink & e);virtual void ShowAll() const;virtual void SetAll();
};
class highfink: public manager, public fink // management fink
{public:highfink();highfink(const std::string & fn, const std::string & ln,const std::string & j, const std::string & rpo,int ico);highfink(const abstr_emp & e, const std::string & rpo, int ico);highfink(const fink & f, int ico);highfink(const manager & m, const std::string & rpo);highfink(const highfink & h);virtual void ShowAll() const;virtual void SetAll();
};

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

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

类方法的实现:emp.cpp:

#include "emp.h"/********abstr_emp**********/abstr_emp::abstr_emp() {fname = "none";lname = "none";job = "none";
}abstr_emp::abstr_emp(const std::string& fn, const std::string& ln,const std::string& j): fname(fn), lname(ln), job(j) {}abstr_emp::~abstr_emp() {}void abstr_emp::ShowAll() const {std::cout << "firstname: " << fname << std::endl;std::cout << "lastname: " << lname << std::endl;std::cout << "job: " << job << std::endl;
}void abstr_emp::SetAll() {std::cout << "Enter firstname: ";std::getline(std::cin, fname);std::cout << "Enter lastname: ";std::getline(std::cin, lname);std::cout << "Enter job: ";std::getline(std::cin, job);
}std::ostream& operator<<(std::ostream& os, const abstr_emp& e) {os << e.lname << " " << e.fname << ", " << e.job;return os;
}/********employee**********/employee::employee() {}employee::employee(const std::string& fn, const std::string& ln,const std::string& j): abstr_emp(fn, ln, j) {}void employee::ShowAll() const { abstr_emp::ShowAll(); }void employee::SetAll() { abstr_emp::SetAll(); }/********manager**********/manager::manager() { inchargeof = 0; }manager::manager(const std::string& fn, const std::string& ln,const std::string& j, int ico): abstr_emp(fn, ln, j), inchargeof(ico) {}manager::manager(const abstr_emp& e, int ico) : abstr_emp(e) {inchargeof = ico;
}manager::manager(const manager& m) : abstr_emp(m) { inchargeof = m.inchargeof; }void manager::ShowAll() const {abstr_emp::ShowAll();std::cout << "Inchargeof: " << inchargeof << std::endl;
}void manager::SetAll() {abstr_emp::SetAll();std::cout << "Enter inchargeof: ";std::cin >> inchargeof;std::cin.get();
}/********fink**********/fink::fink() { reportsto = "none"; }fink::fink(const std::string& fn, const std::string& ln, const std::string& j,const std::string& rpo): abstr_emp(fn, ln, j), reportsto(rpo) {}fink::fink(const abstr_emp& e, const std::string& rpo): abstr_emp(e), reportsto(rpo) {}fink::fink(const fink& f) : abstr_emp(f) { reportsto = f.reportsto; }void fink::ShowAll() const {abstr_emp::ShowAll();std::cout << "Reportsto: " << reportsto << std::endl;
}void fink::SetAll() {abstr_emp::SetAll();std::cout << "Enter reportsto: ";std::getline(std::cin, reportsto);
}/********highfink**********/highfink::highfink() {}highfink::highfink(const std::string& fn, const std::string& ln,const std::string& j, const std::string& rpo, int ico): abstr_emp(fn, ln, j), manager(fn, ln, j, ico), fink(fn, ln, j, rpo) {}highfink::highfink(const abstr_emp& e, const std::string& rpo, int ico): abstr_emp(e), manager(e, ico), fink(e, rpo) {}highfink::highfink(const fink& f, int ico): abstr_emp(f), fink(f), manager((const abstr_emp&)f, ico) {}highfink::highfink(const manager& m, const std::string& rpo): abstr_emp(m), manager(m), fink((const abstr_emp&)m, rpo) {}highfink::highfink(const highfink& h) : abstr_emp(h), manager(h), fink(h) {}void highfink::ShowAll() const {abstr_emp::ShowAll();std::cout << "Inchargeof: " << manager::InChargeOf() << std::endl;std::cout << "Reportsto: " << fink::ReportsTo() << std::endl;
}void highfink::SetAll() {abstr_emp::SetAll();std::cout << "Enter reportsto: ";std::getline(std::cin, fink::ReportsTo());std::cout << "Enter Inchargeof: ";std::cin >> manager::InChargeOf();std::cin.get();
}

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

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

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

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

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

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

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

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

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

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

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

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

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

C++ Primer Plus习题及答案-第十四章相关推荐

  1. C++ Primer Plus习题及答案-第十二章

    习题选自:C++ Primer Plus(第六版) 内容仅供参考,如有错误,欢迎指正 ! c++使用new和delete运算符来动态控制内存. 对于静态成员,要在类声明之外使用单独语句进行初始化,因为 ...

  2. C++ Primer Plus习题及答案-第十五章

    习题选自:C++ Primer Plus(第六版) 内容仅供参考,如有错误,欢迎指正 ! 友元类和嵌套类 RTTI和类型转换运算符 复习题 1. 下面建立友元的尝试有什么错误? a. class sn ...

  3. 机器学习(周志华) 参考答案 第十四章 概率图模型 14.9

    机器学习(周志华西瓜书) 参考答案 总目录 http://blog.csdn.net/icefire_tyh/article/details/52064910 机器学习(周志华) 参考答案 第十四章 ...

  4. 【c++ primer】第五版第十四章习题答案

    第十四章 重载运算与类型转换 练习14.1 在什么情况下重载的运算符与内置运算符有所区别?在什么情况下重载的运算符又与内置运算符一样? 解: 不同点: 重载操作符不保证操作数的求值顺序,例如对& ...

  5. 软件项目管理第4版课后习题[附解析]第十四章

    软件项目管理第4版课后习题[附解析]系列文章目录 第一章 第二章 第三章 第四章 第五章 第六章 第七章 第八章 第九章 第十章 第十一章 第十二章 第十三章 第十四章 第十五章 第十六章 期末复习题 ...

  6. 《C++ Primer》习题参考答案:第6章 - C++模块设计——函数

    专栏C++学习笔记 <C++ Primer>学习笔记/习题答案 总目录 https://blog.csdn.net/TeFuirnever/article/details/10070021 ...

  7. C Primer Plus (第六版) 第十四章_编程练习答案

    no1.c //重新编写复习题5,用月份名的拼写代替月份号(别忘了用strcmp()).在一个简单的程序中测试该函数 # include <stdio.h> # include <s ...

  8. C Primer Plus(第6版)第十四章复习题答案

    1.正确的关键字是struct,最后一条声明语句以及结构模板有花括号要有分号. 2.输出如下 6 1 22 Spiffo Road S p 3.struct month { char name[10] ...

  9. 复频域求零输入响应_第十四章 动态电路的复频域分析 习题答案

    第十四章 动态电路的复频域分析 一.选择题 1. 图13-1所示电感元件的电压.电流关系的运算形式是 B . A .)0()()(-+=L L L Li s sLI s U : B .)0()()(- ...

最新文章

  1. 深入 理解 Statement 和 PreparedStatement
  2. mysql autocommit_【整理】MySQL 之 autocommit
  3. javascript篇-知道value值,返回对象中的key值
  4. Spark _22 _创建DataFrame的几种方式(一)
  5. JavaScript 特效代码集
  6. Druid Monitor监控JavaSE,杀cmd端口进程
  7. 图片转化为base64编码python版本
  8. 33个网站足以使你成为一个天才
  9. 自制hdmi线一头改vga图_最全VGA、DVI、PS/2、USB等接头详解焊接方法
  10. 金蝶系统无法建立数据可连接服务器,金蝶K3打开,提示无法建立数据链接
  11. 2018个人年度工作总结与2019工作计划(互联网)
  12. 华为nova 2 Plus魔镜版语音助手逗趣玩不停
  13. 真爱过的人,不会再有爱~
  14. html5手机电商网页设计代码_一部手机,万物皆可复制粘贴,这位兼职写代码的设计师将AR玩出了新高度...
  15. 关于静态变量的缺省值
  16. php检测txt中重复数据,Python实现检测文件的MD5值来查找重复文件案例
  17. Keras自定义损失函数出现:ValueError: Unknown loss function: focal_loss
  18. 报错:version magic ‘3.10.0_hifone SMP mod_unload ARMv7 p2v8 ‘ should be ‘3.10.0_s40 SMP mod_unload ARM
  19. 计算机网络:网络安全
  20. 无线电能传输LCL-S拓扑/WPT MATLAB/simulink仿真模型 (模型左边为两电平H桥逆变器,LCL-S串联谐振,右边不可控整流结构)

热门文章

  1. 计算机教室防火防盗防潮制度,微机室管理员岗位职责
  2. 多边形彩色教育教学述职报告PPT模板
  3. 好佳居软装十大品牌 软装行业深度理解
  4. 常见的加密算法分类及介绍
  5. 日记侠:不聊天,要朋友圈何用?
  6. 报告显示:修改器、自动点击、破解版是大多数手游里占比最高的外挂类型
  7. 基于 Mathematica 的机器人仿真环境(机械臂篇)
  8. 基于CCG算法的IEEE33配电网两阶段鲁棒优化调度matlab
  9. WARN - Got result of null when trying to get Boolean.
  10. HX-A 型 便携式水质等比例采样器