多繼承帶來的問題

首先看這個頭文件

#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,提供兩個方法,一個是他本是組件的顯示,另一個是基類的顯示)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章