c++ primer plus 多重继承(MI)

39 阅读3分钟

关键的点:

  • 如果继承的基类又都继承于同一个基类,则将会出现二义性,即多重继承的对象包含两个最初的基类对象。
    • 使用虚基类
    • 从多个类(其基类相同)派生出的对象只继承一个基类对象
    • 使用虚基类时构造函数,需显式地调用基类构造(仅在此合法)
  • 方法上的二义性。
    • 作用域解析算符
    • 重新定义方法
      • protected 属性
      • 再继承层次结构中的类可以使用;作为协助公有接口的辅助方法
  • 为什么需要用同样的基类指针或引用去指向不同的子类对象
    • 暂时理解:便于用数组或其它数据结构进行管理

代码

workermi.h

#ifndef WORKERMI_H
#define WORKERMI_H
#include <iostream>
#include <string>
#include<cstdio>
using namespace std;

class Worker
{
private:
    string fullname;
    long id;
protected:
    virtual void Data()const;//如果Data( )方法是保护的,则只能在继承层次结构中的类中使用它,在其他地方则不能使用;作为协助公有接口的辅助方法。
    virtual void Get();
public:
    Worker():fullname("no one"),id(0L){}
    Worker(const string &s, long n):fullname(s),id(n){}
//    virtual ~Worker() =0; //pure virtual function, 有它会报错
    virtual void Set()=0;
    virtual void Show() const  = 0;

};

class Waiter: virtual public Worker
{
private:
    int panache;
protected:
    void Data() const;
    void Get();
public:
    Waiter():Worker(),panache(0){}
    //派生类并不能直接访问基类 的私有数据,而必须使用基类的公有方法才能访问这些数据。
    //访问的方式取决于方法。构造函数使用一种技术,而其他成员函数使用另一种技术。
    //派生类构造函数在初始化基类私有数据时,采用的是成员初始化列 表语法.
    //将基类信息传递给基类构造函数,然后使用构造函数体初始化BrassPlus类新增的数据项。
    //非构造函数不能使用成员初始化列表语法,
    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()const;

};

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 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(){}

};

class SingingWaiter: public Singer,public Waiter
{
protected:
    void Data() const;
    void Get();

public:
    SingingWaiter (){}
    SingingWaiter (const string &s, long n, int p=0, int v=other):Worker(s,n),Waiter(s,n,p),Singer(s,n,v){}//why need Work(s,n)
    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 &sg, int p=0):Worker(sg),Waiter(sg,p),Singer(sg){}
    void Set();
    void Show() const;
//    ~SingingWaiter(){}
};

void test_workerMI();

#endif // WORKERMI_H

workermi.cpp

#include "workermi.h"
#include <cstring>

void Worker::Data()const
{
    cout << "Name: "<<fullname<<endl;
    cout <<"Employee ID"<<id<<endl;
}

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

//waiter methods

void Waiter::Set()
{
    cout<<"Enter waiter's full name: ";
    Worker::Get();
    Get();
}

void Waiter::Show() const
{
    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;
}

//singer methods
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()const
{
    cout<<"category: singer \n";
    Worker::Data();
    Data();
}

void Singer::Get()
{
    cout<< "Enter number for singer's vocal range: \n";
    int i;
    for(i=0;i<Vtypes;++i)
    {
        cout<<i<<": "<<pv[i]<<"   ";
        if(i%4==3)
            cout<<endl;
    }
    if(i%4 !=0)
        cout<<"\n";
    cin>>voice;
    while (cin.get() != '\n')
        continue;
}

void Singer::Data()const
{
    cout<<"Vocal range: "<<pv[voice]<<endl;
}



//singingWaiter methods
void SingingWaiter::Data()const
{
    Singer::Data();
    Waiter::Data();
}

void SingingWaiter::Get()
{
    Waiter::Get();
    Singer::Get();
}

void SingingWaiter::Set()
{
    cout <<"Enter singing waiter's name: ";
    Worker::Get();
    Get();
}

void SingingWaiter::Show() const
{
    cout<<"category: singing waiter \n";
    Worker::Data();
    Data();
}


void test_workerMI()
{
    const int SIZE=5;
    Worker *lolas[SIZE];
    int ct;
    for(ct=0;ct<SIZE;ct++)
    {
        char choice;
        cout << "Enter the employee category:\n "
             << "w: waiter s:singer  "
             << "t: singer waiter  q:quit\n";
        cin>>choice;
        while (strchr("wsqt",choice) ==NULL)
        {
            cout << "Please enter a w, s, t, or q: ";
            cin>>choice;
        }
        if (choice == 'q')
            break;
        switch (choice)
        {
            case 'w' :lolas[ct] =new Waiter;
                break;
            case 's':  lolas[ct] = new Singer;
                break;
            case 't': lolas[ct] = new SingingWaiter;
        }
        cin.get();
        lolas[ct]->Set();
    }

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

关注的地方

strchr 函数用于检测输入的字符

枚举的使用:类内,类外需要加作用域

指针,new和delete