2012-06-26 3 views
0

J'ai un gestionnaire de classe et une classe de base (avec des sous-classes dérivées de Base, disons A: public Base). Inside Manager Je crée la bonne sous-classe de Base, mais Base ignore l'existence de Manager. Je voulais passer dans cette sous-classe créée de Base un objet fonction lié à une méthode membre de la classe Manager pour l'objet A à invoquer. En d'autres termes lors de la création, il serait quelque chose comme ceci:Lier les arguments pour fonctionner en deux étapes en C++?

void Manager::createThing() 
{ 
FunctionObject func; 
if (doExtraWork) 
    func.bind(&Manager::someMethod, this); 

Base *bla = new A(func); 
} 

puis à l'intérieur de A, je voudrais être en mesure de détecter si nous avons un travail supplémentaire pour avoir le report Manager sur nous et faisons, quelque chose comme :

A::update() 
{ 
if (func) //ideally detect if func was bound to someMethod or func is empty 
    func(this); //equivalent to the above instance of manager calling someMethod on this instance of A 

//do regular stuff after; 
} 

Comment puis-je faire cela (probablement avec la fonction boost ou quelque chose comme ça)?

Répondre

2

Si votre type FunctionObject est boost::function<void()>, vous pouvez ensuite attribuer à ce à partir du résultat de boost::bind, quelque chose comme ceci:

boost::function<void()> f = boost::bind(&Manager::someMethod, this); 
Base *b = new A(f); 

où le constructeur de A a la signature A(boost::function<void()>). L'appel d'un boost::function a légèrement plus de frais généraux qu'un appel de fonction virtuelle. Je ne connais pas assez votre situation particulière pour être sûr, mais vous pourriez vous retrouver avec une meilleure interface si vous définissez réellement une classe de base abstraite représentant la fonctionnalité de f, et avez votre constructeur pour Base et A au lieu de prendre un objet de la classe de base abstraite, comme ceci: -

struct ThingDoer 
{ 
    virtual void do() = 0; 
}; 

class Manager : private ThingDoer 
{ 
    virtual void do() 
    { ... } 

    void createThing() 
    { 
     Base *b = new A(this); 
    } 
}; 

où le constructeur de A a la signature A(ThingDoer*).

Si vous avez déjà entendu parler du modèle de conception 'délégué', vous connaissez le genre de chose que je veux dire. Dans cet exemple simple, résumé, il semble juste clunkier et plus longue que la solution à l'aide boost::function, mais il a des avantages potentiels pour le logiciel réel:

  • Il vous permet de donner un nom au type « délégué » ThingDoer, votre mise en œuvre de ce type, et la fonction à l'intérieur. En outre, si vous utilisez Doxygen ou un autre système de commentaire structuré, il est beaucoup plus facile de documenter la classe déléguée qu'un paramètre d'objet fonction.
  • Il vous permet de choisir dans la classe Manager et toutes les classes dérivées d'hériter de ThingDoer ou d'avoir une classe imbriquée (privée ou protégée) qui hérite de ThingDoer.
  • Si vous voulez ajouter une fonction supplémentaire à l'interface plus tard (pour faire deux choses différentes), c'est plus facile à faire, et vous ne serez pas tenté d'ajouter simplement de plus en plus d'objets fonction. (Mais c'est plus facile plus tard parce que vous avez déjà payé le coût supplémentaire de l'écriture de votre code.)
  • Si vous avez des programmeurs des communautés Java ou C#, ils seront probablement plus familiers avec le code comme ceci.

Il se peut qu'aucun d'entre eux ne présente d'avantages dans votre situation, auquel cas, utilisez certainement la solution boost::function/boost::bind. J'ai fait de même dans des situations similaires. Je devrais probablement mentionner aussi que C++ 11 a la plupart ou la totalité de la fonctionnalité de liaison de fonction dans std:: lui-même.

+0

merci réponse impressionnante ... Je vais penser à la chose de délégué .. comme pour la façon de lier .. est-il un moyen pour le conditionnel à l'intérieur de A :: update() pour détecter qu'il est boost :: bind a été lié ou non? Ce serait plus agréable que de passer un pointeur sur une fonction boost :: qui pourrait être nulle (comme je devrais utiliser new) ou une méthode factice factice dans Manager lié à la fonction boost :: –

+0

Lorsque vous évaluez un ' boost :: function' en tant que bool, c'est vrai s 'il a été réglé sur une fonction. Autrement dit, 'if (f) f();' fonctionne comme vous le souhaitez. –

+0

belle merci! –

Questions connexes