C++ Primer Plus章节编程练习第十四章

1

题目

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

typedef std::Valarry<int> ArrayInt;
typedef Pair<ArrayInt,ArryInt> PairArray;

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

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

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

int main(void){
    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.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;
}

  下面是该程序的运行情况:

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
        Years   Bottles
        1988    42
        1994    58
        1998    122
        2001    144
Wine: Gushing Grape Red
        Years   Bottles
        1993    48
        1995    60
        1998    72
Total bottles for Gushing Grape Red: 180
Bye

题解

#include<iostream>
#include<string>
#include<valarray>
using namespace std;
//*******************Pairs模板类声明和定义如下*******************
template<class T1,class T2>
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(){}
};
template<class T1,class T2>
T1& Pair<T1,T2>::first(){
    return a;
}
template<class T1,class T2>
T2& Pair<T1,T2>::second(){
    return b;
}
//*******************Pairs模板类声明和定义如下*******************
class Wine{
private:
    typedef std::valarray<int> ArrayInt;
    typedef Pair<ArrayInt,ArrayInt> PairArray;
    string label;
    int years_cnt;
    PairArray years_bottles;
public:
    Wine(){}
    Wine(const char* l,int y,const int yr[],const int bot[]):
            label(l),years_cnt(y),years_bottles(ArrayInt(yr,y),ArrayInt(bot,y)){}
    Wine(const char* l,int y):
            label(l),years_cnt(y),years_bottles(ArrayInt(y),ArrayInt(y)){}
    ~Wine(){}
    void GetBottles();
    string &Label(){return label;};
    int sum(){return years_bottles.second().sum();}
    void Show()const;
};
void Wine::GetBottles(){
    cout<<"Enter "<<label<<" data for "<<years_cnt<<" year(s):\n";
    for(int i=0;i<years_cnt;++i){
        cout<<"Enter year: ";
        cin>>years_bottles.first()[i];
        cout<<"Enter bottles for that year: ";
        cin>>years_bottles.second()[i];
    }
}
void Wine::Show()const{
    cout<<"Wine: "<<label<<endl;
    cout<<"\tYears\tBottles"<<endl;
    for(int i=0;i<years_cnt;++i){
        cout<<"\t"<<years_bottles.first()[i]<<"\t"<<years_bottles.second()[i]<<endl;
    }
}
int main(void){
    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.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

题目

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

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

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

题解

#include<iostream>
#include<string>
#include<valarray>
using namespace std;
//*******************Pairs模板类声明和定义如下*******************
template<class T1,class T2>
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(){}
};
template<class T1,class T2>
T1& Pair<T1,T2>::first(){
    return a;
}
template<class T1,class T2>
T2& Pair<T1,T2>::second(){
    return b;
}
//*******************Pairs模板类声明和定义如下*******************
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt,ArrayInt> PairArray;
class Wine:private string,private PairArray{
private:
    int years_cnt;
public:
    Wine(){}
    Wine(const char* l,int y,const int yr[],const int bot[]):
            string(l),PairArray(ArrayInt(yr,y),ArrayInt(bot,y)),years_cnt(y){}
    Wine(const char* l,int y):
            string(l),PairArray(ArrayInt(y),ArrayInt(y)),years_cnt(y){}
    ~Wine(){}
    void GetBottles();
    string &Label(){return (string&)(*this);};
    int sum(){return PairArray(*this).second().sum();}
    void Show()const;
};
void Wine::GetBottles(){
    cout<<"Enter "<<(const string&)(*this)<<" data for "<<years_cnt<<" year(s):\n";
    for(int i=0;i<years_cnt;++i){
        cout<<"Enter year: ";
        cin>>((PairArray&)(*this)).first()[i];      //先转为PairArry的引用,再调用方法,注意括号优先级
        cout<<"Enter bottles for that year: ";
        cin>>((PairArray&)(*this)).second()[i];
    }
}
void Wine::Show()const{
    cout<<"Wine: "<<(const string&)(*this)<<endl;
    cout<<"\tYears\tBottles"<<endl;
    for(int i=0;i<years_cnt;++i){
        cout<<"\t"<<PairArray(*this).first()[i]<<"\t"<<PairArray(*this).second()[i]<<endl;
    }
}
int main(void){
    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.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;
}

3

题目

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

题解

//583  14.12    617
#include<iostream>
#include<string>
#include<cstring>
//需要使用的Worker类的相关声明和定义
//****************第一代: 基类Worker的声明****************
class Worker{
private:
    std::string fullname;
    long id;
protected:
    virtual void Data()const;
    virtual void Get();
public:
    Worker():fullname("no one"),id(0L){}
    Worker(const std::string &s,long n):fullname(s),id(n){}
    virtual ~Worker()=0;
    virtual void Set()=0;
    virtual void Show()const=0;
};
//****************第一代: 基类Worker的实现****************
Worker::~Worker(){}
void Worker::Data()const{
    std::cout<<"Name: "<<fullname<<"\n";
    std::cout<<"Employee ID: "<<id<<"\n";
}
void Worker::Get(){
    std::getline(std::cin,fullname);
    std::cout<<"Enter worker's ID: ";
    std::cin>>id;
    while(std::cin.get()!='\n')
        continue;
}
//****************第二代: 派生类Waiter的声明****************
class Waiter:virtual public Worker{
private:
    int panache;
protected:
    void Data()const;
    void Get();
public:
    Waiter():Worker(),panache(0){}
    Waiter(const std::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()const;
};
//****************第二代: 派生类Waiter的定义****************
void Waiter::Data()const{
    std::cout<<"Panache rating: "<<panache<<"\n";
}
void Waiter::Get(){
    std::cout<<"Enter waiter's panache rating: ";
    std::cin>>panache;
    while(std::cin.get()!='\n')
        continue;
}
void Waiter::Set(){
    std::cout<<"Enter waiter's name: ";
    Worker::Get();
    Get();
}
void Waiter::Show()const{
    std::cout<<"Category: waiter\n";
    Worker::Data();
    Data();
}
//****************第二代: 派生类Singer的声明****************
class Singer:virtual public Worker{
protected:
    enum{other,alto,contralto,soprano,bass,baritone,tenor};
    enum{Vtypes=7};
    void Data()const;
    void Get();
private:
    static char*pv[Vtypes];
    int voice;
public:
    Singer():Worker(),voice(other){}
    Singer(const std::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()const;
};
//****************第二代: 派生类Singer的定义****************
char* Singer::pv[]={"other","alto","contralto","soprano","bass","baritone","tenor"};
void Singer::Data()const{
    std::cout<<"Vocal range: "<<pv[voice]<<std::endl;
}
void Singer::Get(){
    std::cout<<"Enter number for singer's vocal range:\n";
    int i;
    for(i=0;i<Vtypes;++i){
        std::cout<<i<<": "<<pv[i]<<"    ";
        if(i%4==3)
            std::cout<<std::endl;
    }
    if(i%4!=0)
        std::cout<<std::endl;
    while(std::cin>>voice&&(voice<0||voice>=Vtypes))
        std::cout<<"Please enter a value >= 0 and < "<<Vtypes<<std::endl;
    while(std::cin.get()!='\n')
        continue;
}
void Singer::Set(){
    std::cout<<"Enter singer's name: ";
    Worker::Get();
    Get(); 
}
void Singer::Show()const{
    std::cout<<"Category: singer\n";
    Worker::Data();
    Data();
}
//****************第三代: 多重继承派生类SingingWaiter的声明****************
class SingingWaiter: public Singer,public Waiter{
protected:
    void Data()const;
    void Get();
public:
    SingingWaiter(){}
    SingingWaiter(const std::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 Waiter&wt,int v=other):
                Worker(wt),Waiter(wt),Singer(wt,v){}
    SingingWaiter(const Singer&ws,int p=0):
                Worker(ws),Waiter(ws,p),Singer(ws){}
    void Set();
    void Show()const;
};
//****************第三代: 多重继承派生类SingingWaiter的定义****************
//把基类的功能模块化,然后在派生类中调用,这样可以防止交叉调用
void SingingWaiter::Data()const{
    Singer::Data();
    Waiter::Data();
}
void SingingWaiter::Get(){
    Waiter::Get();
    Singer::Get();
}
void SingingWaiter::Set(){
    std::cout<<"Enter singing waiter's name: ";
    Worker::Get();
    Get();
}
void SingingWaiter::Show()const{
    std::cout<<"Catraget: singing waiter\n";
    Worker::Data();
    Data();
}

//****************QueeTP模板类的声明和定义****************
template<class T>
class QueeTP{
private:
    int Max_size,front,rear;
    T* queue;
public:
    QueeTP(int size=20){            //size为容量,Max_size为实际使用的空间个数,要比最大的大一个
        Max_size=size+1;
        queue=new T[Max_size];
        front=rear=0;               //初始化
    }
    ~QueeTP(){delete[] queue;}
    int size(){                     //计算大小
        return (rear+Max_size)%Max_size-front;
    }
    bool isempty(){                 //判空
        return front==rear;
    }
    bool isfull(){
        return size()==Max_size-1;  //判满
    }
    bool push(const T &item){       //入队
        if(isfull()) return false;
        queue[rear++]=item;
        rear%=Max_size;
        return true;
    }
    bool pop(T &item){              //出队
        if(isempty()) return false;
        item=queue[front++];
        front%=Max_size;
        return true;
    }
};

//********************测试函数********************
const int SIZE=5;
int main(){
    using namespace std;
    QueeTP<Worker*> q;
    int ct;
    for(ct=0;ct<SIZE;++ct){
        char choice;
        cout<<"Enter the employee category:\n"
            <<"w: waiter s: singer  "
            <<"t: singing waitre  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;
        while(cin.get()!='\n') continue;
        Worker* wp;
        switch(choice){
            case 'w': wp=new Waiter;wp->Set();
                      if(q.isfull())
                        cout<<"queue is full!"<<endl;
                      else
                        q.push(wp);break;
            case 's': wp=new Singer;wp->Set();
                      if(q.isfull())
                        cout<<"queue is full!"<<endl;
                      else
                        q.push(wp);break;
            case 't': wp=new SingingWaiter;wp->Set();
                      if(q.isfull())
                        cout<<"queue is full!"<<endl;
                      else
                        q.push(wp);break;
        }
    }
    while(!q.isempty()){
        Worker* temp;
        q.pop(temp);
        temp->Show();
    }
    cout<<"Bye.\n";
    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的简单程序对它们进行测试。

题解

#include<iostream>
#include<string>
#include<cstdlib>
#include<ctime>
using namespace std;
//*****************虚基类Person的定义和实现*****************
class Person{
private:
    string firstname;
    string lastname;
public:
    Person(){}
    Person(string fn,string ln):firstname(fn),lastname(ln){}
    Person(const char* fn,const char* ln):firstname(fn),lastname(ln){}
    Person(const Person& p):firstname(p.firstname),lastname(p.lastname){}
    virtual ~Person(){}
    virtual void Show()const=0;
};
void Person::Show()const{
    cout<<firstname<<", "<<lastname;
}
//*****************派生类Gunslinger的定义和实现*****************
class Gunslinger:virtual public Person{
private:
    double draw;
    int score;
public:
    Gunslinger(){}
    Gunslinger(string fn,string ln,double dr,int sc):
                Person(fn,ln),draw(dr),score(sc){}
    Gunslinger(const char* fn,const char* ln,double dr,int sc):
                Person(fn,ln),draw(dr),score(sc){}
    Gunslinger(const Gunslinger& gl):Person(gl),draw(gl.draw),score(gl.score){}
    virtual ~Gunslinger(){}
    virtual double Draw()const{return draw;}
    virtual void Show()const;
};
void Gunslinger::Show()const{
    Person::Show();
    cout<<endl;
    cout<<"Draw time: "<<draw<<endl;
    cout<<"Score: "<<score<<endl;
}
//*****************派生类PokerPlayer的定义和实现*****************
class PokerPlayer:virtual public Person{
public:
    PokerPlayer(){}
    PokerPlayer(string fn,string ln):Person(fn,ln){}
    PokerPlayer(const char* fn,const char* ln):Person(fn,ln){}
    virtual ~PokerPlayer(){}
    virtual void Show()const;
    virtual double Draw()const;
};
void PokerPlayer::Show()const{
    Person::Show();
}
double PokerPlayer::Draw()const{
    srand(time(0));
    return rand()%52+1;
}
//*****************多重派生类BadDude的定义和实现*****************
class BadDude:public Gunslinger,public PokerPlayer{
public:
    BadDude(){}
    BadDude(string fn,string ln,double dr,int sc):
        Person(fn,ln),Gunslinger(fn,ln,dr,sc){}
    BadDude(const char* fn,const char* ln,double dr,int sc):
        Person(fn,ln),Gunslinger(fn,ln,dr,sc){}
    BadDude(const Gunslinger& gp):
        Person(gp),Gunslinger(gp){}
    virtual ~BadDude(){}
    virtual void Show()const;
    double Gdraw();
    int Cdraw();
};
void BadDude::Show()const{
    Gunslinger::Show();
}
double BadDude::Gdraw(){
    return Gunslinger::Draw();
}
int BadDude::Cdraw(){
    return PokerPlayer::Draw();
}
int main(){
    const int SIZE=3;
    Person* people[SIZE];
    for(int i=0;i<3;i++){
        string fn,ln;
        double dr;
        int sc;
        cout<<"Please enter the firstname: ";
        cin>>fn;
        cout<<"Please enter the lastname: ";
        cin>>ln;
        switch(i){
            case 0:{
                    cout<<"Please enter the draw time of the Gunslinger: ";
                    cin>>dr;
                    cout<<"Please enter the score of the Gunslinger: ";
                    cin>>sc;
                    people[i]=new Gunslinger(fn,ln,dr,sc);
                    break;
                }
            case 1:{
                    people[i]=new PokerPlayer(fn,ln);
                    break;
                }
            case 2:{
                    cout<<"Please enter the draw time of the BadDude: ";
                    cin>>dr;
                    cout<<"Please enter the score of the BadDude: ";
                    cin>>sc;
                    people[i]=new BadDude(fn,ln,dr,sc);
                    break;
                }
        }
    }
    for(int i=0;i<SIZE;++i){
        people[i]->Show();
        cout<<endl;
        delete people[i];
    }
    Gunslinger gl("Bob","Smith",100,100);
    PokerPlayer pp("Ray","Mack");
    BadDude bd("Genji","Lucy",200,200);
    cout<<gl.Draw()<<endl;
    cout<<pp.Draw()<<endl;
    cout<<bd.Gdraw()<<endl;
    cout<<bd.Cdraw()<<endl;
    return 0;
}

5

题目

  下面是一些类声明:

#include<iostream>
#include<string>
class abstr_emp{
private:
    string fname;
    string lname;
    string job;
public:
    abstr_emp(){};
    abstr_emp(const string &fn,const string &ln,const string &j):
                    fname(fn),lname(ln),job(j){}
    virtual void ShowAll()const;
    virtual void SetAll();
    friend ostream& operator<<(ostream& os,const abstr_emp &e);
    virtual ~abstr_emp()=0;
};
class employee:public abstr_emp{
public:
    employee();
    employee(const string &fn,const string &ln,const string &j):abstr_emp(fn,ln,j){}
    virtual void ShowAll()const;
    virtual void SetAll();
};
class manager:virtual public abstr_emp{
private:
    int inchargeof;
protected:
    int InChargeof()const{return inchargeof;}
    int &InChargeof(){return inchargeof;}
public:
    manager(){};
    manager(const string &fn,const string &ln,const string &j,int ico=0):
            abstr_emp(fn,ln,j),inchargeof(ico){}
    manager(const abstr_emp& e,int ico):
            abstr_emp(e),inchargeof(ico){}
    manager(const manager& m):
            abstr_emp(m),inchargeof(m.inchargeof){}
    virtual void ShowAll()const;
    virtual void SetAll();
};
class fink: virtual public abstr_emp{
private:
    string reportsto;
protected:
    const string ReportsTo()const{return reportsto;}
    string& ReportsTo(){return reportsto;}
public:
    fink(){};
    fink(const string &fn,const string &ln,const string &j,const string &rpo):
        abstr_emp(fn,ln,j),reportsto(rpo){}
    fink(const abstr_emp&e,const string &rpo):
        abstr_emp(e),reportsto(rpo){}
    fink(const fink& e):
        abstr_emp(e),reportsto(e.reportsto){}
    virtual void ShowAll()const;
    virtual void SetAll();
};
class highfink:public manager,public fink{
public:
    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(const abstr_emp& e,const string& rpo,int ico):
            abstr_emp(e),manager(e,ico),fink(e,rpo){}
    highfink(const fink& f,int ico):
            abstr_emp(f),manager((const abstr_emp&)(f),ico),fink(f){}
    highfink(const manager& m,const string rpo):
            abstr_emp(m),manager(m),fink((const abstr_emp&)(m),rpo){}
    highfink(const highfink& h):abstr_emp(h),manager(h),fink(h){}
    virtual void ShowAll()const;
    virtual void SetAll();
};

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

int main(){
    employee em("Trip","Harris","Thumper");
    cout<<em;
    em.ShowAll();
    cout<<endl;
    manager ma("Amorphia","Spindragon","Nuancer",5);
    cout<<ma;
    ma.ShowAll();
    cout<<endl;

    fink fi("Matt","Oggs","Oiler","Juno Barr");
    cout<<fi;
    fi.ShowAll();
    cout<<endl;
    highfink hf(ma,"Gurly 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 * tri[4]={&em,&fi,&hf,&hf2};
    for(int i=0;i<4;i++)
        tri[i]->ShowAll();
    return 0;
}

  为什么没有定义赋值运算符?
  为什么要将ShowAll()和SetAll()定义为虛的?
  为什么要将abstr_emp定义为虛基类?
  为什么highfink类没有数据部分?
  为什么只需要一个operator<<( )版本?
  如果使用下面的代码替换程序的结尾部分,将会发生什么情况?

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

题解

#include<iostream>
#include<string>
using namespace std;
//**************abstr_emp的声明和实现**************
class abstr_emp{
private:
    string fname;
    string lname;
    string job;
public:
    abstr_emp(){};
    abstr_emp(const string &fn,const string &ln,const string &j):
                    fname(fn),lname(ln),job(j){}
    virtual void ShowAll()const;
    virtual void SetAll();
    friend ostream& operator<<(ostream& os,const abstr_emp &e);
    virtual ~abstr_emp()=0;
};
abstr_emp::~abstr_emp(){}

void abstr_emp::ShowAll()const{
    cout<<"Name: "<<fname<<", "<<lname<<endl;
    cout<<"Job: "<<job<<endl;
}
void abstr_emp::SetAll(){
    cout<<"Enter the firstname: ";
    cin>>fname;     cin.get();
    cout<<"Enter the lastname: ";
    cin>>lname;     cin.get();
    cout<<"Enter the job: ";
    getline(cin,job);
}
ostream& operator<<(ostream& os,const abstr_emp &e){
    os<<"Name: "<<e.fname<<", "<<e.lname<<endl;
    os<<"Job: "<<e.job<<endl;
    return os;
}

//**************employee的声明和实现**************
class employee:public abstr_emp{
public:
    employee();
    employee(const string &fn,const string &ln,const string &j):abstr_emp(fn,ln,j){}
    virtual void ShowAll()const;
    virtual void SetAll();
};
void employee::ShowAll()const{
    abstr_emp::ShowAll();
}
void employee::SetAll(){
    abstr_emp::SetAll();
}
//**************manager的声明和实现**************
class manager:virtual public abstr_emp{
private:
    int inchargeof;
protected:
    int InChargeof()const{return inchargeof;}
    int &InChargeof(){return inchargeof;}
public:
    manager(){};
    manager(const string &fn,const string &ln,const string &j,int ico=0):
            abstr_emp(fn,ln,j),inchargeof(ico){}
    manager(const abstr_emp& e,int ico):
            abstr_emp(e),inchargeof(ico){}
    manager(const manager& m):
            abstr_emp(m),inchargeof(m.inchargeof){}
    virtual void ShowAll()const;
    virtual void SetAll();
};
void manager::ShowAll()const{
    abstr_emp::ShowAll();
    cout<<"Inchargeof: "<<inchargeof<<endl;
}
void manager::SetAll(){
    abstr_emp::SetAll();
    cout<<"Enter the number of abstr_emps managed: ";
    cin>>inchargeof;
    cin.get();
}
//**************Fink的声明和实现**************
class fink: virtual public abstr_emp{
private:
    string reportsto;
protected:
    const string ReportsTo()const{return reportsto;}
    string& ReportsTo(){return reportsto;}
public:
    fink(){};
    fink(const string &fn,const string &ln,const string &j,const string &rpo):
        abstr_emp(fn,ln,j),reportsto(rpo){}
    fink(const abstr_emp&e,const string &rpo):
        abstr_emp(e),reportsto(rpo){}
    fink(const fink& e):
        abstr_emp(e),reportsto(e.reportsto){}
    virtual void ShowAll()const;
    virtual void SetAll();
};
void fink::ShowAll()const{
    abstr_emp::ShowAll();
    cout<<"Reportsto: "<<reportsto<<endl;
}
void fink::SetAll(){
    abstr_emp::SetAll();
    cout<<"Enter the name of whom the fink should report to: ";
    getline(cin,reportsto);
}
//**************highfink的声明和实现**************
class highfink:public manager,public fink{
public:
    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(const abstr_emp& e,const string& rpo,int ico):
            abstr_emp(e),manager(e,ico),fink(e,rpo){}
    highfink(const fink& f,int ico):
            abstr_emp(f),manager((const abstr_emp&)(f),ico),fink(f){}
    highfink(const manager& m,const string rpo):
            abstr_emp(m),manager(m),fink((const abstr_emp&)(m),rpo){}
    highfink(const highfink& h):abstr_emp(h),manager(h),fink(h){}
    virtual void ShowAll()const;
    virtual void SetAll();
};
void highfink::ShowAll()const{
    abstr_emp::ShowAll();
    cout<<"Inchargeof: "<<manager::InChargeof()<<endl;
    cout<<"Reportsto: "<<fink::ReportsTo()<<endl;
}
void highfink::SetAll(){
    abstr_emp::SetAll();
    cout<<"Enter the number of abstr_emps managed: ";
    cin>>manager::InChargeof();
    cin.get();
    cout<<"Enter the name of whom the fink should report to: ";
    getline(cin,fink::ReportsTo());
}

int main(){
    employee em("Trip","Harris","Thumper");
    cout<<em;
    em.ShowAll();
    cout<<endl;
    manager ma("Amorphia","Spindragon","Nuancer",5);
    cout<<ma;
    ma.ShowAll();
    cout<<endl;

    fink fi("Matt","Oggs","Oiler","Juno Barr");
    cout<<fi;
    fi.ShowAll();
    cout<<endl;
    highfink hf(ma,"Gurly 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 * tri[4]={&em,&fi,&hf,&hf2};
    for(int i=0;i<4;i++)
        tri[i]->ShowAll();
    return 0;
}

//问答题
//1.为什么没有赋值运算符?
//因为没有动态内存分配,所以默认赋值运算符也可以使用,不会导致错误

//2.为什么要把ShowAll和SetAll定义为虚的?
//因为派生类要对这两个数字进行覆写,所以要定义为虚的

//3.为什么要将abstr_emp定义为虚基类?
//因为abstr_emp派生了manager和fink,而manager和fink又多重派生了highfink,此时为了避免包含多个abstr_emp的副本,所以需要定义为虚基类

//4.为什么highfink类没有数据部分?
//因为是多重派生产生的,所以不需要另外添加成员时,只用继承来的父类的成员即可。

//5.为什么只有一个operator<<()版本?
//operator<<()参数为基类的引用,而基类的引用可以指向派生类,所以只有一个

//6.如果用下面的代码替换程序的结尾部分,将会发生什么情况?
// abstr_emp tri[4]={em,fi,hf,hf2};
// for(int i=0;i<4;i++)
//     tri[i].ShowAll();
//
// 只会显示名字和职业,因为em,fi,hf,hf2会被强制转为abstr_emp类,所以只会使用基类的方法

当珍惜每一片时光~