0

À titre d'exemple à ma question, imaginez une classe de base comme ceci:C++: Sélection d'une classe dérivée par une base à l'aide Surcharger au lieu de Cast dynamique

struct Agent { 

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

}; 

associés à un dérivé comme celui-ci:

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

}; 

et le comparer à cette base:

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; 

}; 

une d ce dérivé:

//forward needed classes..... 

struct PaperAgent: public Agent { 

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

    //etc...... 

}; 

Si je tente d'utiliser ces deux méthodes en passant à la concurrence() fonctionnent une instance polymorphes Agent (référence dans ce cas), seule la première compile. Dans le second cas, le compilateur se plaint qu'il n'y a pas de fonction telle que la concurrence (const Agent &). Je comprends pourquoi cela ne fonctionne pas, mais existe-t-il une alternative qui n'exige pas dynamic_cast et est plus proche du second cas montré ci-dessus en termes de conception? Peut-être un motif de conception que je ne connais pas, ou que je n'ai jamais imaginé pourrait être utilisé pour imiter cela?

+3

Vous pourriez trouver "double expédition" utile – Justin

+0

Y a-t-il une raison pour laquelle vous n'en faites pas une fonction virtuelle qui ne prend aucun paramètre et que la répartition virtuelle appelle la bonne fonction? – NathanOliver

+0

Mes sincères remerciements à Justin et double expédition :) c'était exactement ce que je cherchais. – Dincio

Répondre

1

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

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

};

cela peut être aidé avec le 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; 
}; 

pour réduire la réplication du code.

a1.compete(Agent const& a2) invoque a2.competeWith(a1), qui appelle à son tour a1.compete(a2) en utilisant le type de dynamique a2 et pleine résolution de surcharge.

Ceci est l'une des nombreuses manières standard de faire "double expédition" - agissant virtuellement sur deux arguments à la fois.

+0

Dans le second bloc de code que vous avez posté, vouliez-vous écrire "const WhateverAgent & competitor" (avec WhateverAgent étant un enfant d'Agent, comme RockAgent ou PaperAgent) au lieu de "const Agent & concurrent"? Autrement le programme entrerait juste une boucle comme je l'ai compris ... alors peut-être que je manque quelque chose. – Dincio

+0

@dincio nous gardons les autres surcharges virtuelles pures de 'competitive' dans' Agent', et les implémememt dans les classes leaf. Ce qui précède est en plus. C'est pourquoi j'ai dit "ajouter". Copié vos méthodes d'origine et enlevé "ajouter" pour le rendre plus clair. – Yakk