C++Primer Plus 第十四章代码重用:多重继承14.3

系列文章目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、多重继承14.3

MI描述的是有多个直接基类的类。与单继承一样,公有 MI表示的也是is-a关系。例如,可以从 Waiter类和 Singer 类派生出 SingingWaiter 类:
class SingingWaiter :public waiter,public singer…};
请注意,必须使用关键字 public 来限定每一个基类。这是因为,除非特别指出,否则编译器将认为是
私有派生:class SingingWaiter : public waiter,Singer (…);// Singer is a private base正如本章前面讨论的,私有 M和保护MI可以表示 has-a关系。Student 类的 studenti.h 实现就是一个
这样的示例。下面将重点介绍公有MI。MI可能会给程序员带来很多新问题。其中两个主要的问题是:从两个不同的基类继承同名方法;从两个或更多相关基类那里继承同一个类的多个实例。为解决这些问题,需要使用一些新规则和不同的语法。因此,与使用单继承相比,使用MI更困难,也更容易出现问题。由于这个原因,很多C++用户强烈反对使用 M,一些人甚至希望删除 MI;而喜欢 MI的人则认为,对一些特殊的工程来说,MI很有用,甚至是必不可少的;也有一些人建议谨慎、适度地使用MI。
下面来看一个例子,并介绍有哪些问题以及如何解决它们。要使用M1,需要几个类。我们将定义一个抽象基类 Worker,并使用它派生出 Waiter 类和 Singer 类。然后,便可以使用 MI从 Waiter 类和 Singer 类派生出 SingingWaiter 类(参见图14.3)。这里使用两个独立的派生来使基类(Worker)被继承,这将导致 MI的大多数麻烦。首先声明 Worker、Waiter和 Singer 类,如程序清单 14.7 所示。

在这里插入图片描述

二、程序清单14.7 Worker0.h

// Worker0.h -- working classes 
#ifndef WORKER0_H_
#define WORKER0_H_

#include <string>

class Worker
{
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() = 0;//pure virtual destructor
    virtual void Set();
    virtual void Show() const;
};

class Waiter : public Worker
{
private:
    int panache;
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;
};

class Singer : public Worker
{
protected:
    enum {other, alto, contralto, soprano, bass, baritone, tenor};
    enum {Vtypes = 7};
private:
   const 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;
};
#endif

程序清单14.7的类声明中包含一些表示声音类型的内部常量。一个枚举用符号常量alto、contralto等表示声音类型,静态数组pv存储了指向相应C-风格字符串的指针,程序清单14.8初始化了该数组,并提供了方法的定义。

三,程序清单14.8 worker0.cpp

// worker0.cpp -- working class methods
#include "worker0.h"
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
// Worker methods

// must implement virtual destructor, even if pure
Worker::~Worker() {}

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

// Waiter methods
void Waiter::Set()
{
    Worker::Set();
    cout << "Enter waiter's panache rating: ";
    cin >> panache;
    while (cin.get() != '\n')
        continue;
}

void Waiter::Show() const
{
    cout << "Category: waiter\n";
    Worker::Show();
    cout << "Panache rating: " << panache << "\n";
}

// Singer methods

const char* Singer::pv[] = { "other", "alto", "contralto",
            "soprano", "bass", "baritone", "tenor" };

void Singer::Set()
{
    Worker::Set();
    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 << endl;
    while (cin >> voice && (voice < 0 || voice >= Vtypes))
        cout << "Please enter a value >= 0 and < " << Vtypes << endl;
    while (cin.get() != '\n')
        continue;
}

void Singer::Show() const
{
    cout << "Category: singer\n";
    Worker::Show();
    cout << "Vocal range: " << pv[voice] << endl;
}


程序清单 14.9是一个简短的程序,它使用一个多态指针数组对这些类进行了测试。

四,程序清单14.9 worktest.cpp

// worktest.cpp -- test worker class hierarchy
#include <iostream>
#include "worker0.h"
const int LIM = 4;
int main()
{
    using std::cout;
    using std::cin;
    using std::endl;

   Waiter bob("Bob Apple", 3200, 5);
   Singer bev("Beverly Hills", 3200, 3);
   Waiter w_temp;
   Singer s_temp;
   Worker * pw[LIM] = {&bob, &bev, &w_temp, &s_temp};

   int i;
   for (i = 2; i < LIM; i++)
       pw[i]->Set();
      for (i = 0; i < LIM; i++)
       {
           pw[i]->Show();
           cout << endl;

       }
   cout << "Bye.\n";
   return 0;
   }

在这里插入图片描述

总结

提示:这里对文章进行总结:

这种设计看起来是可行的:使用Waiter指针来调用Waiter::Show()和 Waiter::Set();使用 Singer 指针来调用 Singer::Show( )和 Singer::Set( )。然后,如果添加一个从 Singer 和 Waiter 类派生出的 SingingWaitei类后,将带来一些问题。具体地说,将出现以下问题。
有多少 Worker?
哪个方法?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值