2015-11-15 76 views
2

我希望這個問題還沒有在其他地方得到解答,我確實搜索了一個答案,但是不能很好地規範搜索。C++當派生類沒有從接口實現函數時該怎麼辦

問題是,我有一個武器抽象類武器需要的統計數據(如準確性,損壞等)。這是一個抽象類,因爲有些武器對重裝和破壞有不同的實現方式,但其中大多數武器沒有。

Weapon類具有DoT(結構體)成員以及getDoT成員函數。

問題是,並非所有的武器都有DoT。但是在代碼中的某個時刻,在處理攻擊時,Weapon :: getDoT被調用。當然,我之前添加了「has_DoT()」方法,所以我不處理單元化的DoT對象,但這是一個相當糟糕的解決方案。

處理這個問題的最佳方法是什麼?當並非所有派生對象實際上都擁有抽象類中的成員?

我以爲首先沒有DoT成員/ getDoT成員函數,只是在派生類Weapon_With_DoT上實現它們,但由於我的抽象類是Weapon,我仍然需要檢查是否武器有一個DoT,然後從武器類型轉換爲Weapon_With_DoT來訪問Weapon_With_DoT :: getDoT成員函數。這也是不合理的,只是相反。

我希望問題能夠以足夠清晰的方式解釋。 :)

+0

如果不是所有的武器都有DoT,那麼它可能不應該在頂級抽象類中。是否有武器的子類具有該屬性?我會考慮爲什麼一些武器有這個屬性,有些不是從設計的角度來看。 – Joe

+0

喬是絕對正確的。應該使用頂級抽象類來定義常見行爲。這種差異應該定義在較低的水平。 – Greg

+0

事後看來,只有在界面中定義了常見行爲纔有意義,但如果代碼的其餘部分使用武器作爲界面,您將如何處理該問題? – deso

回答

0

DoT代表損傷時間,對吧?所以我認爲這是一個隨着時間的推移受到傷害統計的物體,它具有損傷量和時間量的屬性。

選項1:空物體

讓武器類具有getDoT方法。沒有DoT的武器仍然可以爲其所有字段返回零和/或中性值的DoT對象。使用DoT並知道這些字段是什麼的代碼可以使用if語句檢測到這種情況,並執行正確的操作(例如,如果損壞量爲零,則在發生任何影響之前返回)。

這將是Null Object pattern的一個示例。

選項2:判斷方法

讓武器類有hasDoT方法返回一個布爾值,並返回了有點的getDoT方法。你說這是你的代碼目前的樣子。我知道這不是一個受歡迎的解決方案,但它很容易理解,並且可以完成工作,所以您不應該爲此感到尷尬。

我可能會添加一個斷言或拋出一個異常來捕獲在沒有DoT的武器上調用getDoT的情況。

選項3:抽象類

getDoT方法中的抽象類。這個類可以是它自己的東西,也可以是Weapon的子類,具體取決於您的應用程序的意義。您可以使用某種形式的動態轉換將Weapon指針轉換爲正確類型的指針。其他答案有關於如何做到這一點的更多細節。

這實際上是最不靈活的選擇,因爲它假定我們知道在編譯時哪些武器具有DoT效應。在你的遊戲的下一個版本中,你可能想要有一種在某個時間點獲得DoT的武器(例如,當用戶切換到不同的模式,或者當它沒有被激發10秒)。如果你作出這樣的決定,你可能必須改變所有代碼的使用選項1或選項2

約絕對的點

我看其他人誰支持選項3說這樣的話「絕對正確」和「故事結束」。你不應該相信他們!設計模式不是規則。有很多方法可以編寫出好的代碼。真正重要的是,您的代碼易於閱讀,易於編寫,易於在將來進行更改,不會造成不必要的危險,並且完成預期的工作。

1

不是所有的武器具有點

然後基類的所有武器不應該提供getDoT。故事結局。

但因爲我的抽象類是武器,我仍然需要進行檢查,看是否該武器有一個點,然後從武器類型強制轉換爲Weapon_With_DoT訪問Weapon_With_DoT :: getDoT

這種方式就是瘋狂。

,而不是代碼,看起來像這樣

if (I can haz DoT) { 
    DoT = gets DoT from weapon somehow // null pointer or optional or dynamic_cast 
    doSomethingImportant(DoT) 
} 

try代碼看起來像這樣

weapon->doSomethingImportant(); 

其中doSomethingImportant是一個虛函數。它在DoT上做了一些事情,或者什麼也不做,或者做一些DoT以外的事情。 你不在乎它在做什麼,你知道這種武器是正確的。

如果由於某種原因無法將doSomethingImportant添加到Weapon(並且可能存在合法原因),請嘗試使用Visitor做同樣的事情。

+0

一般來說,代碼中的任何(是,*任何*,這不是玩笑)'if語句是可疑的,可能應該像上面顯示的那樣替換。例外情況應該很少。 –

+0

如果目標是消除if,那麼我會考慮任何形式的消息傳遞,比如:'weapon-> process(Event(「reload」));' –

+0

@ c-smile這不是一個目標,它意味着達到目的(清潔可維護的代碼)。但是,消息系統也可能有用。 –

1

在像你這樣的情況下,考慮任何種類的運行時多態性都是有意義的。如動態鑄造或這樣的事情:

class Weapon { 
    enum { CLASS_ID: 1 }; 

    public: 
    template<typename T> 
    T* get_interface() { 
     return static_cast<T*>(this->get_interface_by_id(T::CLASS_ID)); 
    } 
    virtual Weapon* get_interface_by_id(int class_id) { 
     if(class_id == CLASS_ID) return this; 
     return nullptr; // no other interfaces by default 
    } 
} 

class WeaponWithDot: public Weapon { 
    enum { CLASS_ID: 2 }; 

    virtual Weapon* get_interface_by_id(int class_id) override { 
     if(class_id == CLASS_ID) return this; 
     return Weapon::get_interface_by_id(class_id); 
    } 
} 

這樣你仍然可以操作武器的情況,並要求動態他們的特點和功能:

Weapon* some = ...; 

WeaponWithDoT* with_dot = some->get_interface<WeaponWithDoT>(); 
if (with_dot) ... 
0

然後取出從Weapon類點數據,以便它仍然是乾淨的,並繼承它作爲DotWeapon。你仍然可以從DotWeapon得到來自對象的Weapon的多晶現象。

我想過沒有在 首位電信部成員/ getDoT成員函數,並且只實現他們在派生類中 Weapon_With_DoT,但因爲我的抽象類是武器,我仍然會 需要檢查看武器是否有DoT,然後從Weapon到Weapon_With_DoT的類型轉換 訪問Weapon_With_DoT :: getDoT 成員函數。這也是不合理的,只是相反。

你完全沒有掌握到多態性。 基類對衍生類應該一無所知。他們只知道他們所包含的內容,他們的派生類填補了空白。

相關問題