2009-09-24 5 views
26

Je me demande s'il est possible de passer une classe en paramètre en C++. Ne passant pas un objet de classe, mais la classe elle-même qui me permettrait d'utiliser cette classe comme ceci.C++ Passage d'une classe en paramètre

void MyFunction(ClassParam mClass) 
{ 
    mClass *tmp = new mClass(); 
} 

Ce qui précède n'est pas du vrai code, mais il explique, je l'espère, ce que j'essaie de faire dans un exemple.

Répondre

37

Vous pouvez utiliser des modèles pour accomplir quelque chose de similaire (mais pas exactement cela):

template<class T> 
void MyFunction() 
{ 
    T *tmp = new T(); 
} 

et appelez avec MyFunction<MyClassName>().

Notez que vous ne pouvez pas utiliser une "variable" à la place de T. Il devrait être connu au moment de la compilation.

19

C++ ne stocke pas de métadonnées sur les classes comme le font d'autres langages. En supposant que vous utilisez toujours une classe avec un constructeur sans paramètre, vous pouvez utiliser des modèles pour réaliser la même chose:

template <typename T> 
void MyFunction() 
{ 
    T* p = new T; 
} 
+0

Comme les autres langues Toutes les langues ne stockent pas de métadonnées sur le programme. C'est une caractéristique relativement nouvelle des langues modernes. –

+1

@Martin, c'est une définition intéressante de "relativement nouveau", compte tenu du fait que Smalltalk, qui était assez courant en son temps, et qui contenait pas mal de code, ne l'a fait que dans les années 70 :) –

+1

choses attribuées à Smalltalk, Lisp était là dans les années 1950 - l'ensemble du programme était une infrastructure de données qui pouvait être inspectée et manipulée. –

0

Vous pouvez créer une méthode de fabrication statique sur votre classe (s) qui retourne simplement une nouvelle instance de la classe et ensuite vous pouvez passer des pointeurs vers cette fonction de manière similaire à ce que vous voulez faire dans votre exemple. Les types de retour sont covariants, donc si toutes vos classes implémentent la même interface, vous pouvez demander au pointeur de la fonction de retourner cette interface. S'ils n'ont pas tous une interface commune, il vous restera probablement void *. De toute façon, si vous avez besoin d'utiliser la sous-classe spécifique, vous devrez dynamic_cast.

2

Vous pouvez également transmettre un pointeur de fonction qui, lorsqu'il est appelé, crée une instance de ce que vous voulez et la renvoie.

void MyFunction(ClassCreatorPtr makeClassFn) 
{ 
    void * myObject = makeClassFn(); 
} 

Vous auriez besoin de le faire retourner un pointeur vers une classe de base pour faire quelque chose de vraiment intéressant avec.

0

Une alternative aux modèles est d'utiliser une fermeture lambda avec C++ 11. Voici ma préférence.

// in header file 
IClass * MyFunctionThatDoesStuff(const IParams & interface_params, 
    std::function<IClass * (const IParams & interface_params)> cls_allocator); 

// in source file 
IClass * MyFunctionThatDoesStuff(const IParams & interface_params, 
    std::function<IClass * (const IParams & interface_params)> cls_allocator) { 
    // Some processing. Perhaps the interface_params are generated 
    // inside this function instead of being passed to it. 
    IClass * mCls = cls_allocator(interface_params); 
    // Do whatever with mCls 
    return mCls; 
} 

// Somewhere else in the code. 
{ 
    Param1Type param1 = whatever1; 
    Param2Type param1 = whatever2; 
    // param1, param2, etc. are parameters that only 
    // SomeClsDerivedFromIClass constructor knows about. The syntax &param1 
    // achieves the closure. 
    // interface_param1 is common to all classes derived from IClass. 
    // Could more than one parameter. These parameters are parameters that 
    // vary from different calls of MyFunctionThatDoesStuff in different 
    // places. 
    auto cls_allocator = 
     [&param1, &param2](const IParams & interface_params)->IClass * { 
      return new SomeCls1DerivedFromIClass(interface_params, 
       param1, param2); 
     }; 
    IClass * mCls = MyFunctionThatDoesStuff(interface_params, 
     cls_allocator); 
} 

// Somewhere else in the code again. 
{ 
    ParamXType paramX = whateverX; 
    ParamYType paramY = whateverY; 
    auto cls_allocator = 
     [&paramX, &paramY](const IParams & interface_params)->IClass * { 
      return new SomeCls2DerivedFromIClass(interface_params, 
       paramX, paramY); 
     }; 
    IClass * mCls = MyFunctionThatDoesStuff(interface_params, 
     cls_allocator); 
} 

L'idée de code ci-dessus fonctionne bien pour un motif de construction rapide ou une variation de motif d'usine. Le lambda est essentiellement une méthode d'usine. Pour le rendre encore plus dynamique, vous pouvez utiliser la saisie automatique des paramètres. Quelque chose comme ça. J'arrive à ceci de l'influence de Python où vous pouvez simplement passer le type de classe à la fonction.

Questions connexes