2010-06-23 3 views
2

J'ai une liste centrale d'implémentations d'une interface et souhaite que les classes dérivées puissent s'enregistrer elles-mêmes dans cette liste sans avoir à les ajouter dans une place centrale. Par exemple:Enregistrement de classes dérivées dans la liste centrale

// interface.h 
struct MyInterface; 
std::vector<MyInterface*>& InterfaceList(); 

struct MyInterface { 
    MyInterface() { 
     InterfaceList().push_back(this); 
    } 
    virtual ~MyInterface() {} 
    // ... 
}; 

// derived.cpp 
#include "interface.h" 
class MyImplementation: public MyInterface { 
public: 
    MyImplementation() { 
    } 
    // ... 
}; 

MyImplementation impl; 

Cela ne semble pas fonctionner. Pour des raisons que je ne comprends pas, le constructeur de MyInterface n'est jamais appelé - j'aurais pensé que l'instance de la classe dérivée l'appelle au démarrage. Je sais qu'il est possible de faire quelque chose dans ce sens puisque j'ai vu d'autres bibliothèques le faire - mais je n'ai pas réussi à comprendre ce que je fais de mal.

Merci :)

Modifier: Désolé, raté une paire de bretelles et une référence. InterfaceList() est une fonction qui renvoie une référence à un vecteur.

Éditer la partie 2: Nous l'avons maintenant fonctionné dans un exemple réduit, mais nous ne pouvons pas le faire fonctionner dans les fichiers pour les implémentations dérivées - mais cette technique fonctionne dans un autre projet. Il doit y avoir quelque chose de légèrement différent dans ces fichiers qui provoque l'échec - mais il semble que le problème ne soit pas dans le code que j'ai posté. Je ne veux pas vraiment afficher de gros morceaux de projets de mon employeur, donc je suppose que je vais devoir continuer à me tripoter. Merci pour les suggestions jusqu'à présent que :)

+0

Où est votre dtor virtuel? vous en avez besoin dans votre classe de base. –

+0

Anders: J'essaie d'afficher une version simplifiée du code, alors j'ai laissé de côté quelques morceaux. Pour les besoins de cette discussion, je m'en fous si ça fuit la mémoire :) – Peter

Répondre

1

Voici la question:

std::vector<MyInterface*> InterfaceList(); 

devrait être

std::vector<MyInterface*> InterfaceList; 
2

Vous exemple ne compile pas sous VS2008. Quel compilateur utilisez-vous? Lorsque vous modifiez la deuxième ligne interface.h à

std::vector<MyInterface*> InterfaceList; 

fonctionne correctement. Lâchez simplement les accolades.

1

Après avoir défini InterfaceList est une sorte de déclaration de fonction qui retourne std :: vecteur

std::vector<MyInterface*> InterfaceList(); 

Remplacez cette

std::vector<MyInterface*> InterfaceList; 
2

J'ai eu un problème similaire récemment et a constaté que la solution la plus simple était de créer une classe de base modèle qui était responsable de l'enregistrement de toutes mes implémentations.

La classe de base contient une variable statique, de type T, et elle est enregistrée dans la liste centrale. Au moment de l'exécution, chaque implémentation créerait son propre objet statique et, en cours de création, elle s'inscrirait dans la liste centrale.

#include <iostream> 
#include <vector> 

class ITestInterface 
{ 
    public: 
     virtual void Execute() = 0; 
}; 

std::vector<ITestInterface *> InterfaceList; 

template <class T> class BaseClass : 
    public ITestInterface 
{ 
    public: 
     virtual void Execute() = 0; 

    protected: 
     BaseClass() 
     { 
      InterfaceList.push_back(&s_thing); 
     } 

    private: 
     static T s_thing; 
}; 

template <class T> T BaseClass<T>::s_thing; 

class ImplementationOne : 
    public BaseClass<ImplementationOne> 
{ 
    public : 
     ImplementationOne(): 
      BaseClass() 
     { 
      ; 
     } 

     void Execute() 
     { 
      std::cout << "ImplementationOne Execute\r\n"; 
     } 
}; 

class ImplementationTwo : 
    public BaseClass<ImplementationTwo> 
{ 
    public : 
     ImplementationTwo(): 
      BaseClass() 
     { 
      ; 
     } 

     void Execute() 
     { 
      std::cout << "ImplementationTwo Execute\r\n"; 
     } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    std::vector<ITestInterface *>::iterator it = InterfaceList.begin(); 
    for(; it != InterfaceList.end(); it++) 
    { 
     (*it)->Execute(); 
    } 
} 

La chose à retenir avec ce code est que la ligne

static T s_thing; 

ne résulte pas en une seule s_thing plutôt parce qu'un modèle est un générateur de type il y a un s_thing statique pour chaque dérivé classe.

La sortie est

ImplementationOne Exécuter

ImplementationTwo Exécuter

Ce code fonctionne dans VS2010.

Questions connexes