2016-01-02 43 views
3

我正在嘗試編寫一個程序,其中ServiceWorker的派生類(例如消防員)可以「對抗」類事件(火災,損傷,搶劫)派生的對象。對抗會返回一個布爾值是否成功。例如,遇到火災的消防員將會成功,但遇到搶劫的消防員不會。 ServiceWorker將跟蹤對抗的數量和成功的對抗,並且有一個對抗方法來確定對抗是否成功。C++在派生類中專門化繼承模板

我想使用特徵來存儲ServiceWorker的每個派生類可以在其類定義中遇到的內容。然而,在ServiceWorker中,對抗方法創建traits類,但是我想將它專門化在派生類中,以便每個派生類只知道它可以面對什麼。

class Incident { }; 
class Fire : Incident { }; 
class Robbery : Incident { }; 
class Injury : Incident { }; 

class ServiceWorker { 
public: 
    ServiceWorker() : ratio(0), num_success(0), num_confronts(0) { 

    } 

    template <typename U> 
    struct can_confront { 
     static const bool result = false; 
    }; 

    double successRatio() { 
    if(ratio) 
      return ratio; 
     else 
      throw; 
    } 
    template <typename T> 
    void confront(T incident) { 
     if(can_confront<T>::result) 
      num_success++; 
     num_confronts++; 

     ratio = num_success/num_confronts; 
    } 
protected: 
    double ratio; 
    unsigned int num_success; 
    unsigned int num_confronts; 
}; 

class Firefighter : public ServiceWorker { 
public: 
    template <> 
    struct can_confront<Fire> { 
     static const bool result = true; 
    }; 
}; 

編輯

所以我設法弄明白。我擺脫了模板並使其面臨虛擬,因此使派生類的ServiceWorker只需要重新定義虛函數並使用ServiceWorker ::對立。我還添加了confront_success()和calc_ratio(),以便更容易地添加新的ServiceWorkers。我讓消防員::對抗()採取消防員事件,從事件繼承。這樣,爲消防員添加新事件將會很容易,因爲他們只需要繼承FirefigherIncident。

class Incident {}; 
class FirefighterIncident : public Incident {}; 
class Fire : public FirefighterIncident {}; 
class RescueCat : public FirefighterIncident {}; 

class ServiceWorker { 
public: 
    ServiceWorker() : ratio(0), num_success(0), num_confronts(0) { 

    } 

    double successRatio() { 
     if(num_confronts != 0) 
      return ratio; 
     else { 
      std::cout << "Can't divide by zero in ratio!" << std::endl; 
      throw; 
     } 
    } 

    virtual void confront(const Incident&) { 
     num_confronts++; 
     calc_ratio(); 
    } 
protected: 
    double ratio; 
    unsigned int num_success; 
    unsigned int num_confronts; 

    void calc_ratio() { 
     ratio = num_success/(double) num_confronts; 
    } 

    void confront_success() { 
     num_success++; 
     num_confronts++; 
     calc_ratio(); 
    } 
}; 

class Firefighter : public ServiceWorker { 
public: 
    using ServiceWorker::confront; 
    virtual bool confront(const FirefighterIncident&) { confront_success(); } 
}; 
+0

不,你不能這樣做,唯一可以在派生類中改變的是虛函數實現和它的返回類型(共變)。由於「對抗」不是虛擬的,我不知道派生類的存在。 –

+0

您需要雙重調度才能擁有'無效的對抗(ServiceWorker&,const Incident&)'。 – Jarod42

+1

@ Jarod42「如果需要運行時多態性,則具有雙重調度」,也就是說。 –

回答

0

在我看來,事情變得更清潔,如果你採取的std::true_typestd::false_type優勢。在基類,

class ServiceWorker { 
public: 
template <typename U> 
struct can_confront: std::false_type { }; 
... 

和在派生類,

class Firefighter: public ServiceWorker { 
public: 
template<typename U> 
struct can_confront: ServiceWorker::template can_confront<U> { }; 
... 

注意,我在派生類(通過繼承)重新定義can_confront,這樣我可以專門它無需專門ServiceWorker::can_confront。要做到這一點,只需添加

template<> 
struct Firefighter::can_confront<Fire>: std::true_type { }; 

類定義。然後confront模板方法一旦if語句替換

if(can_confront<T>::value) 

然而工作,記住,你仍然留下的問題confront總是使用ServiceWorker::can_confront<T>,即使你把它通過Firefighter對象。一個簡單的解決方法是將confront的定義複製到每個派生類中。

+0

這些可能是很好的改進,但它們與問題的要點無關。將模板複製到派生的cassess將無法實現任何內容。 –

+0

@ n.m。除了工作代碼(OP的代碼不能編譯)和他正在尋找的專業化程序之外的任何東西。在我的理解中,這個問題的要點恰恰在於'can_confront'專用於多個派生類。多態性是不可能的,因爲'對抗'不可能是虛擬的,但它可以實現,例如,通過超載,如果真的想要。 – downhillFromHere

+0

是的,最初,我使用多態性使其工作,並在每個事件的數字代碼。當事件傳遞給ServiceWorker時,數字代碼在confront()中被檢查。我認爲這真的是草率的技巧,但我認爲我可以使用特質類來改善它。這樣做的目標是保持相同的多態和繼承能力,同時消除對數字代碼的需求。 – Jonathan