C++ Primer Plus习题及答案-第十四章

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

第十四章- 代码重用笔记

复习题

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

AB
class Bear
class Kitchen
class Person
class Person
class Person, class Automobile
class PolarBear
class Home
class Programmer
class HorseAndJockey
class Driver
AB公有派生还是私有派生合适
class Bearclass PolarBear公有派生,因为北极熊也是一种熊,is-a的关系
class Kitchenclass Home私有派生,因为家中有厨房,has-a的关系
class Personclass Programmer公有派生,因为程序员也是人,is-a的关系
class Personclass HorseAndJockey私有派生,因为马和驯马师的组合包人,has-a的关系
class Person, class Automobileclass 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 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生成了多少个模板类定义?

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 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 << "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 function
    virtual ~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 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:

#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()函数。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艰默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值