2012-08-11 5 views
4

j'ai une classe avec une fonction de membre basé sur un modèle:dérangement combinant les concepts GP et POO

class Person 
{ 
    template <typename TItem> 
    void DoSomething(TItem item) 
    { 
    item.Action(); 
    } 
}; 

Cela me permet de passer tout élément avec une fonction de membre d'action et la personne effectuer cette action avec l'élément. Donc, je pouvais faire:

Person person; 
BaseballBat bat; 
person.DoSomething(bat); 

Cette structure me permet d'appeler des fonctions avec n'importe quel type d'objet. Cependant, si je veux magasin tout type d'objet, je serais à le modèle de la classe:

template <TItem> 
class Person 
{ 
public: 
    void DoSomething() 
    { 
    this->Item.Action(); 
    } 

    void SetItem(TItem item) 
    { 
    this->Item = item; 
    } 
private: 
    TItem Item; 
}; 

Person<BaseballBat> person; 
BaseballBat bat; 
person.SetItem(&bat); 
person.DoSomething(); 

C'est gênant parce que je dois re-instancier la classe personne pour changer le type de objet.

Sinon, je pourrais tirer l'élément d'une classe parente:

class Person 
{ 
public: 
    void DoSomething() 
    { 
    this->Item.Action(); 
    } 

    void SetItem(TItem* item) 
    { 
    this->Item = item; 
    } 

private: 
    ParentItem* Item; 
}; 

class ParentItem{}; 

class BaseballBat : public ParentItem 
{} 

Person person; 
BaseballBat bat; 
person.SetItem(&bat); 
person.DoSomething(); 

Ceci est gênant parce que je dois maintenir la structure d'héritage pour tous les éléments (qui semble très « non-GP »). Le problème vient vraiment quand j'ai plusieurs couches d '"objets qui contiennent des objets" - c'est-à-dire que je devrais "transmettre" les arguments du modèle de fonction d'un appel très "haut niveau" aux classes contenues :

class BaseballBat 
{ 
    void DoAction(); 
}; 

class Child 
{ 
    template <typename TItem> 
    void DoAction(TItem item) 
    { 
    item.DoAction(); 
    } 
}; 

class Person 
{ 
    Child child; 

    // This is annoying to have to pass the item to the person, who then has to pass it to the child. I'd rather "give" the child an Item, then just be able to call child.DoAction(), where the Person doesn't know anything about the item. 
    template <typename TItem> 
    void PlayWithChild(TItem item) 
    { 
    child.DoAction(item); 
    } 
} 

quelqu'un peut-il commenter sur la façon de mélanger correctement ces deux idées de modèles de fonction et stocker des objets comme des données membres? (Ce qui précède ne sont que des exemples ringards pour essayer de démontrer - si elles n'ont pas de sens ou si vous avez de meilleurs exemples, je suis tout ouïe :)).

--------- Modifier --------- Peut-être un meilleur exemple est une simplification de mon cas réel. J'ai un matcher de classe qui a une fonction de membre:

template<typename TDistanceFunctor, typename TPropagationFunctor> 
void Matcher::Compute(TDistanceFunctor distanceFunctor, TPropagationFunctor propagationFunctor); 

Puis-je une autre classe, ImageAlgorithm, qui utilise un matcher:

template<typename TMatcher> 
void ImageAlgorithm::Compute(TMatcher matcher) 
{ 
    matcher.Compute(...); // How do I get the DistanceFunctor and the PropagationFunctor here? 
} 

Je veux appeler ces choses comme:

Je ne sais pas comment "traverser" le DistanceFunctor et PropagationFunctor à travers l'objet ImageAlgorithm afin qu'il puisse accéder à l'objet Matcher à l'intérieur de l'ImageAlgor
Matcher myMatcher; 
.... Setup matcher (how?) ... 
ImageAlgorithm algorithm; 
algorithm.Compute(myMatcher); 

ithm :: Appel de calcul. Bien sûr, je pourrais modéliser Matcher sur TDistanceFunctor et stocker un TDistanceFunctor en tant que variable membre, mais plus tard je ne peux pas changer le foncteur de distance que le matcher utilise pour un autre type de foncteur de distance.

Répondre

1

Vous pouvez essayer d'utiliser boost::any pour contenir vos membres de type-variante.

De la liste:

Le boost :: toutes les classes (...) prend en charge la copie de tout type de valeur et sûr vérifié l'extraction de cette valeur strictement contre son type.

EDIT

Vous avez raison l'invocation du foncteur stocké avec boost tout serait problématique. Donc, je suggère une autre solution: Utilisez std :: function (ou boost :: function) pour envelopper vos foncteurs. De cette façon, Matcher peut contenir des objets de fonction de la syntaxe pertinente (par exemple, aucun paramètre), et n'a pas besoin d'être modélisé sur les types de foncteurs.

L'objet fonction fait déjà la combinaison entre OO (au moins dans un certain sens) et GP pour vous.

+0

Je n'ai jamais vraiment compris où boost :: any est utile - parce que si vous devez connaître le type pour extraire l'objet de boost :: any, alors vous pourriez avoir juste modélisé quelque chose. –

+0

L'idée de boost :: any est que l'interface (qui reçoit la valeur) n'a pas besoin d'être consciente des types concrets possibles que vous utilisez. Vous avez raison de dire qu'il n'y a pas de parallèle à «virtuel» dans ce sens (dans le sens où vous pourriez simplement invoquer une méthode sans prendre soin du type sous-jacent). Vous pourriez avoir une carte de type id à la fonction d'invocation, mais ce serait lourd. J'ai ajouté une solution différente. – Asaf

+0

Cela signifie que je devrais stocker une fonction std :: pour chaque fonction dans mon Matcher, mais est-ce exact? Cela semble lourd (disons que Matcher a 5 fonctions, et puis une autre situation similaire d'un Propagator a 5 fonctions, je devrais stocker 10 fonctions std ::?) –