C++多重继承

在C++里,继承按方式上有private, public和protected继承。常用public继承,public继承简单一些。在public继承里,基类的公用成员在派生类里也将是公有成员。

而我们经常使用public继承来进行多重继承(multiple inheritance),以实现更高效的代码重用。

翻看《C++ Primer Plus 6th》,觉得多重继承是一个比较偏的知识,于是在此做一个笔记。

以《C++ Primer Plus 6th》程序清单14.7为例,来做笔记。现在我们需要处理的类有4个,它们的关系如下图:

worker的多重继承
worker的多重继承,出自《C++ primer plus 6th》P551

我们关键看头文件类的声明。

第一步,由Worker以is-a关系派生出Singer和Waiter,源代码如下。

Worker >(is-a) Singer/Waiter

// multiple inheritance

// worker0.h -- working classes

#ifndef WORKER0_H_
#define WORKER0_H_

#include <string>

class Worker {      // an abstract base class
private:
  /* data */
  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:
  /* data */
  int panache;

public:
  Waiter () : Worker(), panache(0) {}
  Waiter (const std::string & s, long n, int p = 0)
    : Worker(s, n), panache(0) {}
  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:
  /* data */
  static char * pv[Vtypes];     // string equivs of voice types
  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

那我们可以看出,基类Worker是一个抽象类,公有派生出Waiter和Singer。这里没有什么难点。注意,在Singer里,我们声明了几个保护的枚举变量。

但是仅凭以上声明是不足以依据多重继承从Waiter和Singer派生出SingingWaiter。我们还需要将Worker设置为Waiter和Singer的虚基类,这样从这而这派生出的SingingWaiter才能只继承Worker。而且,在调用父类方法时,为了避免歧义(因为SingingWaiter同时派生于Waiter和Singer),所要要用作用域解析运算符指明调用的父类方法。为了使调用更为清晰,在每个类里都声明protected的Data() const和Get()方法,这样就可以打破递增式调用,使用作用域解析运算符选取需要调用的父类方法。

下面再由Waiter和Singer派生出SingingWaiter。

Worker >(is-a) Singer/Waiter >(is-a, multi-inheritance)

// multiple inheritance

// workermi.h -- working classes with MI

#ifndef WORKER0_H_
#define WORKER0_H_

#include <string>

class Worker {      // an abstract base class
private:
  /* data */
  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;     // pure virtual destructor
  virtual void Set() = 0;
  virtual void Show() const = 0;
};

class Waiter : virtual public Worker {
private:
  /* data */
  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(0) {}
  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:
  /* data */
  static char * pv[Vtypes];     // string equivs of voice types
  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

// multiple inheritance
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 & wt, int p = 0)
    : Worker(wt), Waiter(wt, p), Singer(wt) {}
  void Set();
  void Show() const;
};

通过这样,我们声明一个Worker指针,就可以把它初始化为Waiter/Singer/SingingWaiter,使用“->”运算符就可以正确获取到相应的方法,实现多态。

作者: V

Web Dev

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s