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...... 

}; 

を私は最初の1は、コンパイル()(この場合の基準)のエージェント多型のインスタンスを機能競うために渡すことで、これらの2つの方法を使用しようとします。 2番目のケースでは、コンパイラはcompete(const Agent &)のような機能がないと不平を言う。私はなぜこれがうまくいかないのか理解していますが、dynamic_castを必要とせず、上に示した2番目のケースに近いデザインがあります。私が気づいていないデザインパターンや、想像したことのないデザインパターンを使ってこれをエミュレートすることは可能でしょうか?

+3

「ダブルディスパッチ」が便利かもしれません – Justin

+0

パラメータを取らず仮想ディスパッチが正しい機能を呼び出す仮想機能にしない理由はありますか? – NathanOliver

+0

ジャスティンと二重のディスパッチに心から感謝しています:)私が探していたのはexacltlyでした。 – Dincio

答えて

1

変更Agent:PaperAgentで

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; 
}; 

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)は、の動的タイプと完全なオーバーロードの解像度を使用してa1.compete(a2)を呼び出します。

これは、「二重ディスパッチ」を行うための多くの標準的な方法の1つです。

+0

投稿したコードの2番目のブロックで、 "const WhateverAgent&competitor"(WhateverAgentは、Agentの子である、RockAgentやPaperAgentなど)を "const Agent&competitor"の代わりに書くことを意味しましたか?さもなければ、プログラムは私がそれを理解したようにループに入るでしょう...そして多分私は何かを欠いています。 – Dincio

+0

@dincio私たちは、 'Agent'の中で' compete'の他の純粋な仮想オーバーロードを保持し、それらを葉のクラスで実装します。以上が追加されたものです。だから私は "追加"と言った。元のメソッドをコピーし、「追加」を削除してより明確にしました。 – Yakk

関連する問題