C++ primer plus第六版第14章编程练习

本文探讨了C++中模板类、多重继承及虚基类的运用,通过具体实例展示了Pair类、Wine类的模板定义,QueueTp类的模板实现,Worker类的多重继承,以及Person类的虚基类应用。深入解析了类的构造、析构、成员函数的重写与实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.pair.h

#pragma once
#include <iostream>
#include <string>
template<class T1,class T2>
class Pair
{
public:
  Pair() {}
  Pair(const T1& aval,const T2& bval):a(aval),b(bval){}
  T1 first()const { return a; }
  T2 second()const { return b; }
private:
  T1 a;
  T2 b;
};

wine.h

#pragma once
#include <iostream>
#include <valarray>
#include <string>
#include "Pair.h"
using namespace std;

typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;
class Wine
{
public:
  Wine();
  ~Wine();
  Wine(const char* label, int y);
  Wine(const char* label, int y,const int yr[],const int bot[]);
  int sum();
  string& Label() { return m_sLabel; }
  void Show();
  void GetBottles();
private:
  string m_sLabel;
  int m_nNum;
  PairArray m_bottoles;
};

wine.cpp

#include "Wine.h"

Wine::Wine()
{
  m_sLabel = "";
  m_nNum = 0;
}


Wine::~Wine()
{
}
Wine::Wine(const char* label, int y) {
  m_sLabel = *label;
  m_nNum = y;
  ArrayInt year = ArrayInt(y);
  ArrayInt bot = ArrayInt(y);
  m_bottoles = PairArray(ArrayInt(y), ArrayInt(y));
  for (int i = 0; i < y; ++i) {
    m_bottoles.first()[i] = 0;
    m_bottoles.second()[i] = 0;
  }
}
Wine::Wine(const char* label, int y, const int yr[], const int bot[]) {
  m_sLabel = *label;
  m_nNum = y;
  ArrayInt year = ArrayInt(m_nNum);
  ArrayInt bott = ArrayInt(m_nNum);
  for (int i = 0; i < y; ++i) {
    year[i] = yr[i];
    bott[i] = bot[i];
  }
  m_bottoles = PairArray(year,bott);
}
int Wine::sum() {
  int sum = 0;
  for (int i = 0; i < m_nNum; ++i) {
    sum += m_bottoles.second()[i];
  }
  return sum;
}
void Wine::Show() {
  cout << "Wine: " << m_sLabel << endl;
  cout << "   Year     Bottoles" << endl;
  for (int i = 0; i < m_nNum; ++i)
    cout << "   "<< m_bottoles.first()[i] <<"     " << m_bottoles.second()[i]<< endl;
}
void Wine::GetBottles() {
  cout << "Enter " << m_sLabel << " data for " << m_nNum << " year(s):" << endl;
  ArrayInt year = ArrayInt(m_nNum);
  ArrayInt bot = ArrayInt(m_nNum);
  for (int i = 0; i < m_nNum; ++i) {
    cout << "Enter year: ";
    cin >> year[i];
    cout << "Enter bottles for that year: ";
    cin >> bot[i];
  }
  m_bottoles = PairArray(year, bot);
}

main函数:

#include <assert.h>
#include <iostream>
#include "Wine.h"

using namespace std;
int main()
{
  cout << "Enter name of wine:";
  char lab[50];
  cin.getline(lab, 50);
  cout << "Enter numer of years:";
  int yrs;
  cin >> yrs;

  Wine holding(lab, yrs);
  holding.GetBottles();
  holding.Show();

  const int YRS = 3;
  int y[YRS] = { 1993,1995,1998 };
  int b[YRS] = { 48,60,72 };
  Wine more("Gushing Grape Red", YRS, y, b);
  more.Show();
  cout << "Total bottles for " << more.Label() << ": " << more.sum() << endl;
  cout << "Bye\n";

  return 0;
}

2.pair.h修改为:

#pragma once
#include <iostream>
#include <string>
template<class T1,class T2>
class Pair
{
public:
  Pair() {}
  Pair(const T1& aval,const T2& bval):a(aval),b(bval){}
  T1 first()const { return a; }
  T2 second()const { return b; }
  void Set(const T1& aval, const T2& bval) { a = aval; b = bval; }
private:
  T1 a;
  T2 b;
};

wine.h:

#pragma once
#include <iostream>
#include <valarray>
#include <string>
#include "Pair.h"
using namespace std;

typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;
class Wine2:public PairArray,public string
{
public:
  Wine2();
  ~Wine2();
  Wine2(const char* label, int y);
  Wine2(const char* label, int y, const int yr[], const int bot[]);
  int sum();
  string& Label() { return (string&)*this; }
  void Show();
  void GetBottles();
private:
  int m_nNum;
};

wine.cpp:

#include "Wine2.h"


Wine2::Wine2()
{
}


Wine2::~Wine2()
{
}
Wine2::Wine2(const char* label, int y)
  :string(label),PairArray(ArrayInt(y),ArrayInt(y)) {
  m_nNum = y;
  for (int i = 0; i < y; ++i) {
    PairArray::first()[i] = 0;
    PairArray::second()[i] = 0;
  }
}
Wine2::Wine2(const char* label, int y, const int yr[], const int bot[])
  :string(label), PairArray(ArrayInt(y), ArrayInt(y)) {
  m_nNum = y;
  ArrayInt year = ArrayInt(m_nNum);
  ArrayInt bott = ArrayInt(m_nNum);
  for (int i = 0; i < y; ++i) {
    year[i] = yr[i];
    bott[i] = bot[i];
  }
  PairArray::Set(year,bott);
}
int Wine2::sum() {
  int sum = 0;
  for (int i = 0; i < m_nNum; ++i) {
    sum += PairArray::second()[i];
  }
  return sum;
}
void Wine2::Show() {
  cout << "Wine: " << (const string)*this << endl;
  cout << "   Year     Bottoles" << endl;
  for (int i = 0; i < m_nNum; ++i)
    cout << "   " << PairArray::first()[i] << "     " << PairArray::second()[i] << endl;
}
void Wine2::GetBottles() {
  cout << "Enter " << (const string)*this << " data for " << m_nNum << " year(s):" << endl;
  ArrayInt year = ArrayInt(m_nNum);
  ArrayInt bot = ArrayInt(m_nNum);
  for (int i = 0; i < m_nNum; ++i) {
    cout << "Enter year: ";
    cin >> year[i];
    cout << "Enter bottles for that year: ";
    cin >> bot[i];
  }
  PairArray::Set(year, bot);
}

main函数与之前相同。

3.模板类定义和实现都要放在头文件中,不然编译会报错。

queuetp.h:

#pragma once
#include <iostream>
using namespace std;
template<class T>
class QueueTp
{
public:
  QueueTp(int qs = Q_SIZE);
  ~QueueTp();
  bool IsEmpty()const;
  bool IsFull()const;
  int count() const;
  bool enqueue(const T& item);
  bool dequeue(T& item);
private:
  struct Node 
  {
    T item;
    Node* next;
  };
  enum { Q_SIZE = 10 };
  Node* front;
  Node* rear;
  int items;
  const int qsize;
  QueueTp(const QueueTp& q):qsize(0){}
  QueueTp& operator=(const QueueTp& q) { return *this; }
};

template<class T>
QueueTp<T>::QueueTp(int qs) :qsize(qs){
  front = rear = NULL;
  items = 0;
}
template<class T>
QueueTp<T>::~QueueTp() {
  Node* temp;
  while (front != NULL) {
    temp = front;
    front = front->next;
    delete temp;
  }
}
template<class T>
bool QueueTp<T>::IsEmpty()const { return items == 0; }
template<class T>
bool QueueTp<T>::IsFull()const { return items == qsize; }
template<class T>
int QueueTp<T>::count() const { return items; }
template<class T>
bool QueueTp<T>::enqueue(const T& item) {
  if (IsFull()) {
    cout << "queue is already full!\n";
    return false;
  }
  Node* add = new Node;
  add->item = item;
  add->next = NULL;
  items++;
  if (front == NULL)
    front = add;
  else
    rear->next = add;
  rear = add;
  return true;
}
template<class T>
bool QueueTp<T>::dequeue(T& item) {
  if (IsEmpty()) {
    cout << "queue is empty!\n";
    return false;
  }
  item = front->item;
  items--;
  Node* temp = front;
  front = front->next;
  delete temp;
  if (items == 0)
    rear = NULL;
  return true;
}

worker.h:

#pragma once
#include <string>
using namespace std;
class Worker
{
public:
  Worker():fullname("no one"),id(0L){}
  Worker(const string& s,long n):fullname(s),id(n){}
  virtual ~Worker();
  virtual void Set() = 0;
  virtual void Show() = 0;
protected:
  virtual void Data()const;
  virtual void Get();
private:
  string fullname;
  long id;
};
class Waiter :virtual public Worker {
public:
  Waiter():Worker(),panache(0){}
  Waiter(const 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();
protected:
  void Data()const;
  void Get();
private:
  int panache;
};
class Singer:virtual public Worker
{
public:
  Singer() :Worker(), voice(other) {}
  Singer(const 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();
protected:
  enum{other,alto,contralto,soprano,bass,baritone,tenor};
  enum{Vtypes = 7};
  void Data()const;
  void Get();
private:
  static char* pv[Vtypes];
  int voice;

};
class SingingWaiter:public Singer, public Waiter {
public:
  SingingWaiter(const string& s, long n, int p = 0,int v = other)
  :Worker(s,n),Waiter(s,n,p),Singer(s,n,v){}
  SingingWaiter(const Worker& wk, int p = 0, int v = other)
  :Worker(wk),Waiter(wk,p),Singer(wk,v){}
  SingingWaiter(const Worker& wk, int p = 0)
  :Worker(wk), Waiter(wk, p), Singer(wk) {}
  SingingWaiter(){}
  void Set();
  void Show();
protected:
  void Data()const;
  void Get();
};

 worker.cpp:

#include <iostream>
#include "Worker.h"
using namespace std;

Worker::~Worker()
{
}
void Worker::Data()const {
  cout << "Name:" << fullname << endl;
  cout << "ID: " << id << endl;
}
void Worker::Get() {
  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(){
  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* Singer::pv[Singer::Vtypes] = { "other","alto","contralto","soprano"
,"bass","baritone","tenor" };
void Singer::Set() {
  cout << "Enter singer's name: ";
  Worker::Get();
  Get();
}
void Singer::Show(){
  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 = 0;
  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::Set() {
  cout << "Enter singing waiter's name: ";
  Worker::Get();
  Get();
}
void SingingWaiter::Show() {
  cout << "Category: singing waiter\n";
  Worker::Data();
  Data();
}
void SingingWaiter::Data()const {
  Singer::Data();
  Waiter::Data();
}
void SingingWaiter::Get() {
  Waiter::Get();
  Singer::Get();
}

main:

#include <iostream>
#include "Worker.h"
#include "QueueTp.h"
const int SIZE = 20;
using namespace std;
int main()
{
  QueueTp<Worker*>* wo = new QueueTp<Worker*>(SIZE);
  for (int i = 0; i < SIZE+1; ++i) {
    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;
    Waiter * w;
    Singer* s;
    SingingWaiter * sw;
    switch (choice)
    {
    case 'w':
      w = new Waiter;
      w->Set();
      wo->enqueue(w);
      break;
    case 's':
      s = new Singer;
      s->Set();
      wo->enqueue(s);
      break;
    case 't':
      sw = new SingingWaiter;
      sw->Set();
      wo->enqueue(sw);
      break;
    default:
      assert(false);
      break;
    }
    cout << "queue has " << wo->count() << " members.\n";
  }
  Worker* temp;
  wo->dequeue(temp);
  temp->Show();
  cout << "Bye.\n";

  return 0;
}

4. person.h:

#pragma once
#include <string>
#include <iostream>
using namespace std;
class Person
{
public:
  Person(string f, string l) :first_name(f), last_name(l) {}
  ~Person();
  virtual void Show();
private:
  string first_name;
  string last_name;
};

class Gunslinger : virtual public Person
{
public:
  Gunslinger(string f, string l,int d):Person(f,l),dents(d){}
  double Draw();
  virtual void Show();
private:
  int dents;
};

class PokerPlayer :virtual public Person
{
public:
  PokerPlayer(string f, string l) :Person(f,l) {}
  int Draw();
};

class BadDude : public PokerPlayer,public Gunslinger
{
public:
  BadDude(string f, string l, int d):Person(f,l),PokerPlayer(f,l),Gunslinger(f,l,d){}
  double Gdraw();
  int Cdraw();
  void Show();
};

person.cpp:

#include "Person.h"

void Person::Show()
{
  cout << "the person's fullname is " << last_name << " " << first_name <<endl;
}

Person::~Person()
{
}

double Gunslinger::Draw() { return (rand() % 10) / 10; }

void Gunslinger::Show(){
  cout << "the Gunslinger's time is " << Draw() << " ,there are " << dents << " dents in his gun.";
  Person::Show();
}

int PokerPlayer::Draw() { return rand() % 52; }

int BadDude::Cdraw() { return PokerPlayer::Draw(); }
void BadDude::Show() {
  cout << "the BadDude's next card is " << Gdraw() << " ,time is " << Cdraw() << ".";
  Person::Show();
}

double BadDude::Gdraw(){  return Gunslinger::Draw();}

 main:

#include <iostream>
#include <vector>
#include "Person.h"
const int SIZE = 20;
using namespace std;
int main()
{
  std::vector<Person*> ps;
  for (int i = 0; i < SIZE; ++i) {
    char choice;
    cout << "Enter the person category:\n"
      << "g:Gunslinger p:PokerPlayer b:BadDude q:quit\n";
    cin >> choice;
    while (strchr("gpbq", choice) == NULL) {
      cout << "Please enter g p,b,or q:";
      cin >> choice;
    }
    if (choice == 'q')
      break;
    Gunslinger * g;
    PokerPlayer* pp;
    BadDude * bd;
    string l, f;
    int d;
    cout << "Enter the person's lastname:";
    cin >> l;
    cout << "Enter the person's firstname:";
    cin >> f;
    switch (choice)
    {
    case 'g':
      cout << "Enter the dents' number:";
      cin >> d;
      g = new Gunslinger(f,l,d);
      ps.push_back(g);
      break;
    case 'p':
      pp = new PokerPlayer(f,l);
      ps.push_back(pp);
      break;
    case 'b':
      cout << "Enter the dents' number:";
      cin >> d;
      bd = new BadDude(f, l, d);
      ps.push_back(bd);
      break;
    default:
      assert(false);
      break;
    }
    cout << endl;
  }
  cout << "All of people are:\n";
  for (auto p : ps) {
    p->Show();
  }
  cout << "Bye.\n";

  return 0;
}

 

5. employee.cpp

#include<iostream>
#include "employee.h"
using namespace std;

abstr_emp::abstr_emp() {
  fname = "";
  lname = "";
  job = "";
}
abstr_emp::abstr_emp(const string& fn, const string& ln, const string& j):fname(fn),lname(ln),job(j) {}
void abstr_emp::ShowAll() const {
  cout << "abstr_emp:" << endl;
  cout << "first name is: " << fname << " last name is: " << lname << " job is: " << job << endl;
}
abstr_emp::~abstr_emp() {}
void abstr_emp::SetAll() {
  cout << "Enter first name:";
  getline(cin, fname);
  cout << "Enter last name:";
  getline(cin, lname);
  cout << "Enter job:";
  getline(cin, job);
}
ostream& operator<<(ostream& os, const abstr_emp& e) {
  os << e.fname <<"."<< e.lname << e.job;
  return os;
}

employee::employee():abstr_emp() {}
employee::employee(const string& fn, const string& ln, const string& j):abstr_emp(fn, ln, j) {}
void employee::ShowAll() const { 
  cout << "employee:" << endl;
  abstr_emp::ShowAll();
}
void employee::SetAll() { abstr_emp::SetAll(); }

manager::manager():abstr_emp(), inchargeof(0) {}
manager::manager(const string& fn, const string& ln, const 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 {
  cout << "manager:" << endl;
  abstr_emp::ShowAll();
  cout << "inchargeof is: " << inchargeof << endl;
}
void manager::SetAll() {
  abstr_emp::SetAll();
  cout << "Enter inchargeof:";
  cin>> inchargeof;
}

fink::fink():abstr_emp(),reportsto("") {}
fink::fink(const string& fn, const string& ln, const string& j, const string& rpo) :abstr_emp(fn, ln, j) { reportsto = rpo; }
fink::fink(const abstr_emp& e, const string& rpo):abstr_emp(e) {reportsto = rpo;}
fink::fink(const fink& e) : abstr_emp(e){ reportsto = e.reportsto; }
void fink::ShowAll() const {
  cout << "fink:" << endl;
  abstr_emp::ShowAll();
  cout << "reportsto is: " << reportsto << endl;
}
void fink::SetAll() {
  abstr_emp::SetAll();
  cout << "Enter reportsto:";
  getline(cin,reportsto);
}

highfink::highfink():abstr_emp(),manager(),fink() {}
highfink::highfink(const string& fn, const string& ln, const string& j, const 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 string& rpo, int ico):abstr_emp(e),manager(e,ico),fink(e,rpo) {}
highfink::highfink(const fink& e, int ico):abstr_emp(e),manager(e,ico),fink(e) {}
highfink::highfink(const manager& m, const string& rpo):abstr_emp(m),manager(m),fink(m,rpo) {}
highfink::highfink(const highfink& e):abstr_emp(e),manager(e),fink(e) {}
void highfink::ShowAll() const {
  cout << "highfink:" << endl;
  abstr_emp::ShowAll();
  cout << "reportsto is: " << fink::ReportsTo() << "inchargeof is: " << manager::InChargeOf() << endl;;
}
void highfink::SetAll() {
  manager::SetAll();
  cout << "Enter reportsto:";
  getline(cin, fink::ReportsTo());
}

employee.h:

#pragma once
#include <iostream>
#include <string>
using namespace std;
class abstr_emp {
public:
  abstr_emp();
  abstr_emp(const string& fn, const string& ln, const string& j);
  virtual void ShowAll() const;
  virtual void SetAll();
  friend ostream& operator<<(ostream& os, const abstr_emp& e);
  virtual ~abstr_emp() = 0;
private:
  string fname;
  string lname;
  string job;
};
class employee:public abstr_emp
{
public:
  employee();
  employee(const string& fn, const string& ln, const string& j);
  virtual void ShowAll() const;
  virtual void SetAll();
};

class manager:virtual public abstr_emp
{
public:
  manager();
  manager(const string& fn, const string& ln, const string& j, int ico = 0);
  manager(const abstr_emp& e, int ico);
  manager(const manager& m);
  virtual void ShowAll() const;
  virtual void SetAll();
protected:
  int InChargeOf()const { return inchargeof; }
  int& InChargeOf(){ return inchargeof; }
private:
  int inchargeof;
};

class fink:virtual public abstr_emp
{
public:
  fink();
  fink(const string& fn, const string& ln, const string& j,const string& rpo);
  fink(const abstr_emp& e, const string& rpo);
  fink(const fink& e);
  virtual void ShowAll() const;
  virtual void SetAll();
protected:
  const string ReportsTo()const { return reportsto; }
  string& ReportsTo(){ return reportsto; }
private:
  string reportsto;
};
class highfink :public manager, public fink {
public:
  highfink();
  highfink(const string& fn, const string& ln, const string& j, const string& rpo,int ico);
  highfink(const abstr_emp& e, const string& rpo,int ico);
  highfink(const fink& e, int ico);
  highfink(const manager& m, const string& rpo);
  highfink(const highfink& e);
  virtual void ShowAll() const;
  virtual void SetAll();
};

main函数:

#include <iostream>
#include "employee.h"
const int SIZE = 5;
using namespace std;
int main()
{
  employee em("Trip", "Harris", "Thumper");
  cout << em << endl;
  em.ShowAll();
  manager ma("Amorphia", "Sindragon", "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* tr[4] = { &em,&fi,&hf,&hf2 };
  for (int i = 0; i < 4; ++i)
    tr[i]->ShowAll();
  return 0;
}

输出为:

 类本身会生成赋值操作符,例子中的所有类中没有指针成员,不需要深拷贝,可使用默认的赋值操作。

ShowAll和SetAll定义为虚拟的,在类继承中,子类可对这两个函数重写,不重写的子类调用基类的实现。

将abstr_emp定义为虚基类则多重继承(MI)时派生类就只有一个基类的子对象。

highfink类没有数据部分是因为继承自基类的数据成员满足该类的功能需求。

此处operator<<定义为友元,而友元函数不能继承,在需要的地方定义即可,不用担心继承关系而重定义以满足不同类的不同需求。 

使用新的方法,则调用ShowAll时调用的是基类abstr_emp的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值