2009-09-24 32 views
26

Me pregunto si es posible pasar una clase como parámetro en C++. No pasando un objeto de clase, pero la clase en sí misma me permitiría usar esta clase de esta manera.C++ Pasar una clase como parámetro

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

Lo anterior no es un código real, pero con suerte explica lo que estoy tratando de hacer en un ejemplo.

Respuesta

37

Puede utilizar plantillas para lograr algo similar (pero no exactamente eso):

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

y llama con MyFunction<MyClassName>().

Tenga en cuenta que de esta manera, no puede usar una "variable" en lugar de T. Debería conocerse en tiempo de compilación.

19

C++ no almacena metadatos sobre clases como lo hacen otros lenguajes. Suponiendo que utilice siempre una clase con un constructor sin parámetros, se puede utilizar plantillas para lograr la misma cosa:

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

Como otros lanaguages ​​ No todos los idiomas almacenan metadatos sobre el programa. Esta es una característica relativamente nueva de los idiomas modernos. –

+1

@Martin, esa es una definición interesante de "relativamente nuevo", teniendo en cuenta que Smalltalk, que era bastante convencional en su época, y tenía bastante código escrito, lo hizo en los años 70 :) –

+1

Como con muchos cosas atribuidas a Smalltalk, Lisp estuvo allí en la década de 1950: todo el programa era una estructura de datos que podía ser inspeccionada y manipulada. –

0

Se puede crear un método de fábrica estática en su clase (s) que simplemente devuelve una nueva instancia de la clase y luego puede pasar punteros a esa función de manera similar a lo que quiere hacer en su ejemplo. Los tipos de devolución son covariantes, por lo que si todas las clases implementan la misma interfaz, puede hacer que el puntero de función devuelva esa interfaz. Si no todos tienen una interfaz común, probablemente te quedarás con la devolución de void *. De cualquier manera, si necesita usar la subclase específica, tendrá que dynamic_cast.

2

También podría pasar un puntero de función que, cuando se invoca, crea una instancia de lo que desee y lo devuelve.

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

que había necesidad de tener que devolver un puntero a una clase base para hacer algo realmente interesante con él.

0

Una alternativa a las plantillas es usar un cierre lambda con C++ 11. Esta es mi preferencia.

// 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); 
} 

La idea del código anterior funciona bien para un patrón de generador rápido o alguna variación de patrón de fábrica. La lambda es básicamente un método de fábrica. Para que sea aún más dinámico, puede usar automático para escribir parámetros. Algo como esto.

auto * MyFunctionThatDoesStuff(const auto & interface_params, 
    std::function<auto * (const auto & interface_params)> cls_allocator); 

Estoy hablando de la influencia de Python, donde puede pasar el tipo de clase a la función.

Cuestiones relacionadas