2009-11-19 51 views
2

我無法決定的方式,以這種類型的關係進行建模......建模「可選」繼承

所有的老闆可以做某些事情,有一些事情(速度,健康等),所以這些是「主要」抽象老闆階層的一部分。

class Boss // An abstract base class 
{ 
    //Stuff that all Bosses can do/have and pure virtual functions 
}; 

現在我要指定幾個純虛函數和成員,可以拍攝的老闆。我想知道我應該如何建模?我已經考慮從Boss類派生出ShootingBoss類,但是具體的Boss本身就是類(而Boss只是它們派生自的抽象基類)。因此,如果ShootingBoss來自Boss,並且特定的Boss來自ShootingBoss,該老闆將無法訪問Boss類中的受保護數據。

Boss(ABC) -> ShootingBoss(ABC) -> SomeSpecificBoss(can't access protected data from Boss?) 

基本上,我想知道推薦的方法來建模這是什麼。任何幫助表示讚賞。如果需要更多信息,我很樂意提供。

+1

SomeSpecificBoss可以訪問老闆的保護成員。 SomeSpecificBoss不直接派生,只要它以某種方式派生。 – hirschhornsalz 2009-11-20 00:00:20

+0

謝謝。出於某種原因,我認爲保護只有一級。 – Anonymous 2009-11-20 00:06:05

+0

@drhirsch - 實際上,如果ShootingBoss是從Boss私下繼承的,那麼SomeSpecificBoss將無法訪問Boss中的任何受保護成員。 – LeopardSkinPillBoxHat 2009-11-20 00:23:26

回答

2

我想你需要看看Mixin類。

例如,您可以創建以下類別:

class Boss { 
    // Here you will include all (pure virtual) methods which are common 
    // to all bosses, and all bosses MUST implement. 
}; 

class Shooter { 
    // This is a mixin class which defines shooting capabilities 
    // Here you will include all (pure virtual) methods which are common 
    // to all shooters, and all shooters MUST implement. 
}; 

class ShootingBoss : public Boss, public Shooter 
{ 
    // A boss who shoots! 
    // This is where you implement the correct behaviour. 
}; 

混入需要multiple inheritance使用,並且有很多陷阱和複雜性來這樣做。我建議你看看this one等問題的答案,以確保你避免這些陷阱。

+0

謝謝,我不確定這是否能與我正在嘗試做的工作一起工作,但仍然有用。 – Anonymous 2009-11-20 00:22:43

1

爲什麼不開始使用接口?所以,不是簡單的超級基礎類,而是將你的東西分散到能力中。

struct IBoss : public IObject 
{ 
} 
struct ICanShoot : public IObject 
{ 
} 

通常爲了實現這個,你從另一個接口派生你的接口,它允許你查詢一個接口。

struct IObject 
{ 
int getId(); // returns a unique ID for this interface. 
int addRef(); 
int release(); 
bool queryInterface(int id, void** pp); 
} 

這樣一來,你更輕鬆地實現你的老闆:

class Boss : public IBoss, public ICanShoot 
{ 
}; 

這可能是矯枉過正了一些,但是如果你的類heirachy是所有搞砸了,這是擺脫困境的最佳途徑。

看看M $的IUnknown界面。

+0

IObject的子類應聲明父級爲虛擬。否則多重繼承是不可能的。如果需要在IObject中使用非默認構造函數,這將會變得非常複雜 – Gayan 2009-11-20 01:08:53

1

這樣做有兩種不同的方式:
1)密新類(已經說明)
2)角色扮演類。
角色扮演有其優點和缺點。角色,該對象可以玩(老闆,射手,無論)是使用遏制實施的。它們必須來自共同的基礎接口類,它必須被動態地降低(argh ..)。調用者會向你的類的對象提供角色指針(這是downcast將進入的地方),如果對象可以扮演角色(返回的非NULL指針),客戶端將調用角色的適當功能。 角色扮演方法的主要優點(避免多重繼承) - 它是動態的。對象可以在運行時接受新的角色,而不是必須在編譯時定義的混入。
此外它是可擴展的。在多重繼承(混入)的方法,如果您決定擴大您的層次結構與「Protector」,並說,老闆可以簡單BossShootingBossProtectingBossShootingProtectingBoss,後來與СowardBossShootingBossProtectingBossShootingProtectingBossCowardBoss展開ufrther ,CowardShootingBossCowardProtectingBoss,CowardShootingProtectingBoss) - 您看到您的層次結構爆炸。這是當你需要切換到角色扮演模式時,對象只需要接受新角色Coward。但是直到你確定你需要它 - 堅持mixin類。 下面是角色扮演lcases層次草圖:

class IRole 
{ 
// some very basic common interface here 
public: 
virtual ~IRole() {} 
}; 

class IBoss : public IRole 
{ 
}; 

class IShooter : public IRole 
{ 
}; 

class IProtector : public IRole 
{ 
}; 

class MultifunctionalPerson 
{ 
public: 
bool AcceptRole(IRole* pRole); // pass some concrete role here 
IRole* GetRole(int roleID); 
}; 


// your clinet will be using it like that 
MultifunctionalPerson& clPerson = ... (coming from somewhere); 

// dynamic_cast below may be replaced with static_cast if you are sure 
// that role at PROTECTOR_ROLE location is guaranteed to be of IProtector type or NULL 
IProtector* pProtector = dynamic_cast<IProtector*>(clPerson.GetRole(PROTECTOR_ROLE)); 
if(0 != pProtector) 
{ 
pProtector->DoSomething(); 
}