2021-04-19 C++ Primer Plus 第十四章 C++中的代码重用 编程练习

编程练习

1.Wine 类有一个string 类对象成员和一个Pair对象;其中前者用于存储葡萄酒的名称,而后者有两个valarry对象,这两个valarray对象分别保存了葡萄酒的酿造年份和该年生产的瓶数。

Winec.h

//
// Created by a1358 on 2021/4/9.
//

#ifndef WINE_WINEC_H
#define WINE_WINEC_H
#include 
#include 

using namespace std;
template 
class Pair
{
private:
    T1 a;
    T2 b;
public:
    T1 & first();
    T2 & second();
    T1 first() const { return a; }
    T2 second() const { return b; }
    Pair(const T1 & aval, const T2 & bval) : a(aval), b(bval) { }
    Pair() {}
};

typedef std::valarray ArrayInt;
typedef Pair PairArray;

class Wine {
private:
    string wine_name;
    PairArray year_count;
    int years;
public:
    Wine();
    ~Wine();
    Wine(const char * l, int y, const int yr[], const int bot[]);
    Wine(const char * l, int y);
    void GetBottle();
    void Show();
    string & Label();
    int sum();

};


#endif //WINE_WINEC_H

Winec.cpp

//
// Created by a1358 on 2021/4/9.
//

#include "Winec.h"
#include 

template
T1 & Pair::first()
{
    return a;
}

template
T2 & Pair::second()
{
    return b;
}

Wine::Wine() {
    wine_name = "MOUTAI";
    year_count=PairArray(ArrayInt(0),ArrayInt(0));
    years = 0;
}

Wine::~Wine() {

}

Wine::Wine(const char *l, int y, const int *yr, const int *bot) {
    wine_name = l;
    years = y;
    year_count=PairArray(ArrayInt(yr,y),ArrayInt(bot,y));
\
}

Wine::Wine(const char *l, int y) {
    wine_name = l;
    years = y;
    year_count=PairArray(ArrayInt(0),ArrayInt(0));
}

void Wine::GetBottle() {
    cout << "Enter " << wine_name << " data for "
         << years << " year(s):" << endl;
    for(int i = 0; i < years; i++)
    {
        cout << "Enter year: ";
        cin >> year_count.first()[i];
        cout << "Enter bottles for that year: ";
        cin >> year_count.second()[i];
    }
}

void Wine::Show() {
    cout << "Wine: " << wine_name << endl;
    cout << "\tYear" <<"\tBottles" << endl;
    for(int i = 0; i < years; i++)
    {
        cout << "\t" << year_count.first()[i]
            << "\t" << year_count.second()[i] << endl;
    }
}

string & Wine::Label() {
    return wine_name;
}

int Wine::sum() {
   return year_count.second().sum();
}

main.cpp

#include 
#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);
    holding.GetBottle();
    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.采用私有继承而不是包含来完成编程练习1。同样,一些typedef可能会有所帮助,另外,您可能还需要考虑诸如下面这样的语句的含义;

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

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

Winec.h

//
// Created by a1358 on 2021/4/9.
//

#ifndef WINE_WINEC_H
#define WINE_WINEC_H
#include 
#include 

using namespace std;
template 
class Pair
{
private:
    T1 a;
    T2 b;
public:
    T1 & first();
    T2 & second();
    T1 first() const { return a; }
    T2 second() const { return b; }
    Pair(const T1 & aval, const T2 & bval) : a(aval), b(bval) { }
    Pair() {}
};

typedef std::valarray ArrayInt;
typedef Pair PairArray;

class Wine : private PairArray,
             private string {
private:
    int years;
public:
    Wine()
    :string(nullptr),years(0),PairArray(ArrayInt(0),ArrayInt(0)){}
    ~Wine(){}
    Wine(const char * l, int y, const int yr[], const int bot[])
    :string(l),years(y),PairArray(ArrayInt(yr,y),ArrayInt(bot,y)){}
    Wine(const char * l, int y)
    :string(l),years(y),PairArray(ArrayInt(y),ArrayInt(y)){}

    void GetBottle();
    void Show();
    string & Label();
    int sum();

};


#endif //WINE_WINEC_H

Winec.cpp

//
// Created by a1358 on 2021/4/9.
//

#include "Winec.h"
#include 

template
T1 & Pair::first()
{
    return a;
}

template
T2 & Pair::second()
{
    return b;
}

void Wine::GetBottle() {
    cout << "Enter " << *this << " data for "
         << years << " year(s):" << endl;
    for(int i = 0; i < years; i++)
    {
        cout << "Enter year: ";
        cin >> this->first()[i];
        cout << "Enter bottles for that year: ";
        cin >> this->second()[i];
    }
}

void Wine::Show() {
    cout << "Wine: " << *this << endl;
    cout << "\tYear" <<"\tBottles" << endl;
    for(int i = 0; i < years; i++)
    {
        cout << "\t" << this->first()[i]
            << "\t" << this->second()[i] << endl;
    }
}

string & Wine::Label() {
    return *this;
}

int Wine::sum() {
    return this->second().sum();
}

main.cpp

#include 
#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);
    holding.GetBottle();
    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;
}

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

QueueTp.h

#include 
class Worker   // an abstract base class
{
private:
    std::string fullname;
    long id;
public:
    Worker() : fullname("no one"), id(0L) {}
    Worker(const std::string & s, long n)
            : fullname(s), id(n) {}
    virtual ~Worker() {}
    virtual void Set();
    virtual void Show() const;
};

template
class QueueTp
{
private:
    enum {Q_SIZE = 10};
    struct Node
    {
        T item;
        Node * next;
    };
    // class members
    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 enqueue(const T & item);
    bool dequeue(T & item);
};


template 
QueueTp::QueueTp(int qs) : qsize(qs)
{
    front = rear = NULL;
    items = 0;
}

template 
QueueTp::~QueueTp()
{
    Node * temp;
    while (front != NULL)
    {
        temp = front;
        front = front->next;
        delete temp;
    }
}

template 
bool QueueTp::enqueue(const T & item)
{
    if(isfull())
        return false;
    Node * add = new Node;
    if (front == NULL)  // if queue is empty
    {
        add->item = item;
        add->next = NULL;
        front = rear = add;
    }
    else
    {
        add->item = item;
        add->next = NULL;
        rear->next = add;
        rear = add;
    }
    items++;

    return true;
}

template 
bool QueueTp::dequeue(T & item)
{
    if(isempty())
        return false;

    item = front->item;
    Node * temp;
    temp = front;
    front = front->next;
    delete temp;
    items--;

    return true;
}


QueueTp.cpp

//
// Created by a1358 on 2021/4/12.
//

#include "QueneTp.h"

#include 
using std::cout;
using std::cin;
using std::endl;

void Worker::Set()
{
    cout << "Enter worker's name: ";
    getline(cin, fullname);
    cout << "Enter worker's ID: ";
    cin >> id;
    while (cin.get() != '\n')
        continue;
}

void Worker::Show() const
{
    cout << "Name: " << fullname << "\n";
    cout << "Employee ID: " << id << "\n";
}

main.cpp

#include 
#include 

#include "QueneTp.h"

const int SIZE = 10;

int main() {
    using std::cin;
    using std::cout;
    using std::endl;
    using std::strchr;

    QueueTpq(3);

    if(q.isempty())
        cout << "Queue is empty" << endl;

    cout << "add worker1 to queue..." << endl;
    Worker w1("shao", 1);
    q.enqueue(w1);

    Worker w;
    cout << "delete worker1..." << endl;
    q.dequeue(w);
    w.Show();

    return 0;
}

4.Person类保存人的名和姓。除构造函数外,它还有Show()方法,用于显示名和姓。Gunslinger类以Person类为虚基类派生而来,它包含一个Draw()成员,该方法返回一个double值,表示枪手的拔枪时间...

Person.h

//
// Created by a1358 on 2021/4/12.
//

#ifndef PERSON_PERSON_H
#define PERSON_PERSON_H

#include 
using std::string;

class Person {
private:
    string firstname;
    string lastname;
public:
    Person():firstname("null"),lastname("null"){}
    Person(const string &f,const string &l):firstname(f),lastname(l){}
    virtual void Set();
    virtual ~Person() = 0;
    virtual void Show() ;
};

class Gunslinger :virtual public Person
{
private:
    int count;
public:
    Gunslinger():Person(),count(0){}
    Gunslinger(const string &f,const string &l,int c):Person(f,l),count(c){}
    virtual void Set();
    int Draw();
    virtual void Show();
};

struct card{
    string color;
    int value;
};

class PokePlayer :virtual public Person
{
private:
public:
    card Draw();
    virtual void Set();
    virtual void Show();
};

class BadDude : public Gunslinger, public PokePlayer{
public:
    BadDude(){};
    BadDude(const string & f,const string & l,int c):Person(f,l),Gunslinger(f,l,c){}
    virtual void Set();
    int Gdraw();
    card Cdraw();
    virtual void Show();
};



#endif //PERSON_PERSON_H

Person.cpp

//
// Created by a1358 on 2021/4/12.
//

#include 
#include "Person.h"
#include 

using std::cout;
using std::endl;
using std::cin;

Person::~Person() {

}

void Person::Set() {
    cout <<"Enter firstname: ";
    cin >> firstname;
    cout << endl;
    cout << "Enter lastname: ";
    cin >> lastname;
    cout << endl;
}

void Person::Show() {
    cout << "firstname: " << firstname << endl
         << "lastname: " << lastname << endl;
}

int Gunslinger::Draw() {
    void srand (unsigned int seed);
    int a = rand() % 10;
    return a;
}

void Gunslinger::Set() {
    Person::Set();
    cout << "Enter counts: ";
    cin >> count;
    cout << endl;
}

void Gunslinger::Show() {
    Person::Show();
    cout << "spear time: " << Draw() << endl
         << "nicks: " << count << endl;
}

card PokePlayer::Draw() {
    card poke;
    poke.color = "Club";
    poke.value = 10;
    return poke;
}

void PokePlayer::Set() {
    Person::Set();
}

void PokePlayer::Show() {
    Person::Show();
    cout << "card color: " << Draw().color << endl
         << "card value: " << Draw().value << endl;
}

int BadDude::Gdraw() {
    void srand (unsigned int seed);
    int a = rand() % 10;
    return a;
}

card BadDude::Cdraw() {
    card c;
    c.value = 6;
    c.color = "Heart";
    return c;
}
void BadDude::Set() {
    Person::Set();
}
void BadDude::Show() {
    Person::Show();
    cout << "spear time: " << Gdraw() << endl;
    cout << "card color: " << Cdraw().color << endl
         << "card value: " << Cdraw().value << endl;
}

main.cpp

#include 
#include 
#include "Person.h"
const int SIZE = 3;

int main()
{
    using std::cin;
    using std::cout;
    using std::endl;
    using std::strchr;

    Person * lolas[SIZE];

    int ct;
    for (ct = 0; ct < SIZE; ct++)
    {
        char choice;
        cout << "Enter the employee category:\n"
             << "g: Gunslinger  p: PokePlayer  "
             << "b: BadDude   q: quit\n";
        cin >> choice;
        while (strchr("gpbq", choice) == NULL)
        {
            cout << "Please enter a g, p, b, or q: ";
            cin >> choice;
        }
        if (choice == 'q')
            break;
        switch(choice)
        {
            case 'g':   lolas[ct] = new Gunslinger;
                break;
            case 'p':   lolas[ct] = new PokePlayer;
                break;
            case 'b':   lolas[ct] = new BadDude;
                break;
        }
        cin.get();
        lolas[ct]->Set();
    }

    cout << "\nHere is your staff:\n";
    int i;
    for (i = 0; i < ct; i++)
    {
        cout << endl;
        lolas[i]->Show();
    }
    for (i = 0; i < ct; i++)
        delete lolas[i];
    cout << "Bye.\n";
    return 0;
}

5.下面是一些类声明

#include 
#include 

class abstr_emp {
private:
    std::string fname;
    std::string lname;
    std::string job;
public:
    abstr_emp();
    abstr_emp(const std::string & fn, const std::string & ln,
              const std::string & j);
    virtual void ShowAll() const;
    virtual void SetAll();
    friend std::ostream &
             operator<<(std::ostream & os, const abstr_emp & e);
    virtual ~abstr_emp() = 0;
};

class employee: public abstr_emp
{
public:
    employee();
    employee(const std::string & fn, const std::string & ln,
             const std::string & j);
    virtual void ShowAll() const;
    virtual void SetAll();
};

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

class fink : virtual public abstr_emp
{
private:
    std::string reportersto;
protected:
    const std::string ReportsTo() const {return reportersto;}
    std::string & ReportsTo() {return reportersto;}
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 mananger, public fink
{
public:
    highfink();
    highfink(const std::string & fn, const std::string &ln,
             const std::string & j, const std::string & rpo,
             int ico);
    highfink(const abstr_emp & e,const std::string & rpo,int ico);
    highfink(const fink & f,int ico);
    highfink(const mananger &m, const std::string & rpo);
    highfink(const highfink & h);
    virtual void ShowAll() const;
    virtual void SetAll();
};


请提供类方法的实现,并在一个程序中对这些类进行测试。下面是一个小型测试程序:

#include 
using namespace std;
#include "emp.h"

int main(void) {
    employee em("Trip","Harris","Thumper");
    cout << em << endl;
    em.ShowAll();
    mananger 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");
    hf.ShowAll();
    cout << "Press a key for next phare:\n";
    cin.get();
    highfink hf2;
    hf2.ShowAll();

    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;
}

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

string类中包含了赋值运算符

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

因为把基类的成员函数定义为虚后,程序将根据引用或指针指向的对象的类型来选择方法,所以当定义基类指针或引用后,在派生类中可以调用相对应的虚成员函数。

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

虚基类使得从多个类(它们的基类相同)派生出的对象只继承一个基类对象。派生类hignfink只会继承一个abstr_emp对象。

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

highfink类继承了mananger和fink的保护域和公有域的作为数据部分。

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

因为mananger和fink类继承了abstr_emp的operator<<函数

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

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

em,fi,hf,hf2这四个派生类对象将被强制转化为基类,而abstr_emp为虚基类,无法创建对象,所以程序会报错,

“invalid abstract type 'abstr_emp' for 'tri'”!。

你可能感兴趣的:(2021-04-19 C++ Primer Plus 第十四章 C++中的代码重用 编程练习)