首先看這個頭文件
#ifndef WORKER0_H_
#define WORKER0_H_
#include<iostream>
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;
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):Worker(s,n),panache(p){}
waiter(const Worker & w,int p):Worker(w),panache(p){}
~waiter(){}
void Set();
void Show()const;
};
class singer:public Worker
{
protected:
enum{other,alto,contralto,soprano,bass,baritone,tenor};
enum{Vtypes=7};
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 &w,int v=other):Worker(w),voice(v){}
void Set();
void Show()const;
};
#endif
假如從Singer和Waiter中公有派生出SingingWaiter類,將會帶來什麼問題呢?
首先,SingingWaiter有多少個Worker組件?因爲Singer和Waiter都從Worker中繼承了組件,然後兩者都派生出了SingingWaiter,那麼這個類就會有兩個Worker組件。
解決方法是使用虛基類。
虛基類使得從多個類(有共同的基類)派生出的對象只繼承一個基類對象。用法如下:
class Singer:virtual public Worker{};
class Waiter:virtual public Worker{};
然後,這樣就可以使用多繼承了:class SingingWaiter:public Singer,public Waiter{};
現在,SingingWaiter對象只包含worker對象的一個副本。
第二個問題,關於構造函數的問題:
對於構造函數的初始化列表,折成應該是這樣進行的:
SingingWaiter(CONST Worker &wk,int p=0,int v=Singer::other):Waiker(wk,p),Singer(wk,v){}
但是,這樣會引起一個問題,將wk傳遞給Worker的時候,會經過兩條路徑(waiter和singer)。爲避免這種衝突,C++在基類是虛的時候,禁止信息經過中間類自動傳遞給基類。因此,上述構造函數將初始化成員panache和voice,但wk參數中的信息將不會傳遞給子對象Waiter。然而編譯器必須在構造派生對象前構造基類對象組件;在上述情況下,編譯器將使用Worker的默認構造函數。
如果不希望默認構造函數來構造虛基類對象,則需要顯式地調用所需的基類構造函數。因此,構造函數應該是這樣的:
SingingWaiter(const Worker & wk,int p=0,int v=Singer::other):Worker(wk),Waiter(wk,p),Singer(wk,v){}
上述代碼將顯式地調用構造函數worker
多繼承還會引起函數調用的二義性。例如,SingingWaiter中沒有新加的成員,所以可以不用重新定義show(),但是,在但繼承中,可以直接調用最近的父類的函數,可現在是多繼承,有兩個父類,那麼,將使用那個呢?
這事,有兩種解決方法,可以使用作用於解析運算符,但是,最好還是重新定義。
但是重新定義還有個小問題:
void SingingWaiter::show()
{
Singer::Show();
Waiter::Show();
}
這樣講顯式名字兩次如何解決呢?
一種方法是使用模塊化方式,而不是遞增方式,即提供貨源一個只顯示Worker組件的方法和一個只顯示Waiter組件或Singer組件的方法。然後再SingingWaiter方法中將組件組合起來。(就是Waiter只顯示他自己的組件,然後定義一個show,提供兩個方法,一個是他本是組件的顯示,另一個是基類的顯示)