class CWatch
{
// 錶
};
class CMechanicalWatch : public CWatch
{
// 機械錶
};
class CQuartzWatch : public CWatch
{
// 石英錶
};
class CHybridWatch : public CMechanicalWatch, public CQuartzWatch
{
// 利用石英操控更精準的混合式機械錶
};
這時會產生一個尷尬的情況,CHybridWatch 內含有兩份 CWatch,所以我們若要用基底類別指標指向最未層的衍生類別時,必須轉型指定
CHybridWatch hw;
CWatch *whA = (CMechanicalWatch*)&hw;
CWatch *whB = (CQuartzWatch*)&hw;
雖然可以這麼做,但一支普通的錶不太需要兩支時針、兩支分針、兩個殼,我們希望只有一份 CWatch 存在,這時可以加入 virtual 關鍵字
class CWatch
{
// 錶
};
class CMechanicalWatch : virtual public CWatch
{
// 機械錶
};
class CQuartzWatch : public virtual CWatch
{
// 石英錶
};
class CHybridWatch : public CMechanicalWatch, public CQuartzWatch
{
// 利用石英操控更精準的混合式機械錶
};
可以發現,virtual 的位置可以放在前面或後面都沒關係,如此在 CHybridWatch 中就只會有一份 CWatch,但以下的程式碼會發現一個問題
class CWatch
{
// 錶
CWatch(int w);
};
class CMechanicalWatch : virtual public CWatch
{
// 機械錶
CMechanicalWatch(int m, int w) : CWatch(w);
};
class CQuartzWatch : public virtual CWatch
{
// 石英錶
CQuartzWatch(int q, int w) : CWatch(w);
};
class CHybridWatch : public CMechanicalWatch, public CQuartzWatch
{
// 利用石英操控更精準的混合式機械錶
CHybridWatch(int h, int m, int q, int w) :
CMechanicalWatch(m, w), CQuartzWatch(q, w)
};
一般情況下,由於建構 CWatch 有透過機械、石英兩條路,為免衝突,同時也為了在機械、石英兩個衍生類別建構前先完成 CWatch 的建構,所以 CWatch 只能使用預設的建構式來建構。
但在虛擬繼承的情況下,我們可以明確的指定基底建構式如
class CHybridWatch : public CMechanicalWatch, public CQuartzWatch
{
// 利用石英操控更精準的混合式機械錶
CHybridWatch(int h, int m, int q, int w) :
CMechanicalWatch(m, w), CQuartzWatch(q, w), CWatch(w);
};
這種明確指定建構式的語法只限定虛擬繼承,其餘情況是會產生語法錯誤的。
此外若機械錶、石英錶有 polymorphism 的情況存在,例如 Stop();
CHybridWatch 若要使用 Stop() 就必須指定明確的基底類別
void CHybridWatch::Stop()
{
CMechanicalWatch::Stop();
CQuartzWatch::Stop();
}
這是合法的,但我們不需要停止兩次指針,這時解決方法是產生更細緻動作的 function
class CWatch
{
// 錶
virtual void Stop() = FALSE;
};
class CMechanicalWatch : virtual public CWatch
{
// 機械錶
protected:
StopHandSet(); // 停止指針
public:
Stop() {StopHandSet(); /*後續動作*/};
};
class CQuartzWatch : public virtual CWatch
{
// 石英錶
protected:
StopPower(); // 停止電源
public:
Stop() {StopPower(); /*後續動作*/};
};
class CHybridWatch : public CMechanicalWatch, public CQuartzWatch
{
// 利用石英操控更精準的混合式機械錶
public:
Stop()
{
CMechanicalWatch::StopHandSet();
CQuartzWatch::StopPower();
/*後續動作*/
};
};
比較特別的技巧大概就是特別製作的 function 我們製作為 protected 成員,這可以讓此函式只允許第一層的衍生類別使用。
沒有留言:
張貼留言