2017-07-14 26 views
0

作爲一個例子,以我的問題,設想一個基類,如下所示:C++:通過一個基地選擇派生類使用超載而不是動態角色

struct Agent { 

    void compete(const Agent& competitor) const = 0; 

}; 

關聯與衍生這樣的:

struct RockAgent; 
struct PaperAgent; 

struct ScissorsAgent: public Agent { 

    void compete(const Agent& competitor) const override { 
     if(dynamic_cast<const RockAgent*>(&competitor)) 
      std::cout << "I have lost" << std::endl; 

     else if(dynamic_cast<const PaperAgent*>(&competitor)) 
      std::cout << "I have won!" << std::endl; 

     //etc.... 
    } 

}; 

和比較,在此基礎:

struct PaperAgent; 
struct RockAgent; 
struct ScissorsAgent; 

struct Agent { 

    void compete(const PaperAgent& competitor) const = 0; 
    void compete(const RockAgent& competitor) const = 0; 
    void compete(const ScissorsAgent& competitor) const = 0; 

}; 

的d此派生:

//forward needed classes..... 

struct PaperAgent: public Agent { 

    void compete(const PaperAgent& competitor) const override { 
     std::cout << "I have won!" << std::endl; 
    } 

    //etc...... 

}; 

如果我試圖通過傳遞到競爭(使用這兩種方法)函數(在這種情況下,參考)代理態實例只有第一個編譯。在第二種情況下,編譯器抱怨沒有競爭的功能(const Agent &)。我明白爲什麼這不起作用,但是有沒有其他替代方案不需要dynamic_cast,並且更接近上面在設計方面顯示的第二種情況?也許我不知道的設計模式,或者我從未想象過的設計模式可以用來模擬這種模式?

+3

您可能會發現有用的「雙重調度」 – Justin

+0

有沒有什麼理由讓它不成爲一個不帶參數並且虛擬調度調用正確函數的虛函數? – NathanOliver

+0

我誠摯地感謝賈斯汀和雙倍派遣:)這無疑是我所尋找的。 – Dincio

回答

1

變化Agent

struct Agent { 
    virtual void competeWith(const Agent& competitor) const = 0; 
    void compete(const Agent& competitor) const { compeditor.competeWith(*this); } 
    virtual void compete(const PaperAgent& competitor) const = 0; 
    virtual void compete(const RockAgent& competitor) const = 0; 
    virtual void compete(const ScissorsAgent& competitor) const = 0; 
}; 

在PaperAgent:

struct PaperAgent: public Agent { 
    void competeWith(const Agent& competitor) const override final { 
    compeditor.compete(*this); 
    } 
    void compete(const PaperAgent& competitor) const final override; 
    void compete(const RockAgent& competitor) const final override; 
    void compete(const ScissorsAgent& competitor) const final override; 

};

這可能與CRTP有所幫助:

template<class D> 
struct AgentImpl: public Agent 
    void competeWith(const Agent& competitor) const override final { 
    compeditor.compete(*static_cast<D const*>(this)); 
    } 
}; 
struct PaperAgent: public AgentImpl<PaperAgent>{ 
    void compete(const PaperAgent& competitor) const final override; 
    void compete(const RockAgent& competitor) const final override; 
    void compete(const ScissorsAgent& competitor) const final override; 
}; 

減少代碼複製。

a1.compete(Agent const& a2)調用a2.competeWith(a1),後者依次調用a1.compete(a2)使用動態類型a2和全重載分辨率。

這是執行「雙重調度」的許多標準方法之一 - 實際上對兩個參數一次起作用。

+0

在你發佈的第二塊代碼中,你是不是要寫「const WhateverAgent&competitor」(WhateverAgent是Agent的任何孩子,比如RockAgent或PaperAgent)而不是「const Agent&competitor」?否則,程序會按照我理解的方式進入一個循環......然後,也許我錯過了一些東西。 – Dincio

+0

@dincio我們在'Agent'中保留'conte'的其他純虛擬重載,並在葉類中實現它們。以上是另外的。這就是爲什麼我說「添加」。複製你的原始方法,刪除「添加」使其更加清晰。 – Yakk