2009-10-08 13 views
5

¿Cómo se simula el comportamiento de C# typeof-command en C++?Cómo escribir en C++

ejemplo de C#:

public static PluginNodeList GetPlugins (Type type) 
{ 
... 
} 

Llamar:

PluginManager.GetPlugins (typeof(IPlugin)) 

cómo implementar esta usando C++? ¿Tal vez las bibliotecas QT o Boost ofrecen una solución?

¿Qué tal si desea implementar .GetPlugins (...) de forma que cargue ese tipo de objetos desde un archivo (.so o .dll)?

+0

¿Qué pasa con la segunda parte de mi pregunta. Para mí es el más difícil y un problema que enfrento una y otra vez. Sería muy apreciado si alguien pudiera indicarme la dirección correcta. –

Respuesta

2

Si desea un comportamiento tipográfico completo, debería usar RTTI (run-time type information). En muchos compiladores, debe activar explícitamente el uso de RTTI, ya que incurre en sobrecarga en tiempo de ejecución.

Luego puede usar typeid o dynamic_cast para buscar el tipo de objeto.

Si no desea utilizar typeid, tendrá que usar herencia, indicadores y/o sobrecargas. Boost podría ayudarlo, pero no es demasiado difícil.

Ejemplo 1:

class Iplugin { ... } 

class Plugin1 : public Iplugin { ... } 
class Plugin2 : public Iplugin { ... } 

void getplugins(Iplugin* p) { 
    // ... you don't know the type, but you know 
    // what operations it supports via Iplugin 
} 

void getplugins(Plugin1& p) { 
    // expliticly handle Plugin1 objects 
} 

Como se puede ver, hay varias formas de evitar el uso de RTTI y typeid.

+1

Es importante que la conversión tenga lugar sobre una clase con un vtable, RTTI depende de él para realizar dynamic_cast. – fbrereto

+1

No creo que RTTI incurra en una sobrecarga de tiempo de ejecución. Más bien, el código generado es un poco más grande, porque la información extra por clase necesita almacenarse con el vtable. Como se mencionó, la clase debe tener un vtable. Dicha clase debería tener casi siempre un destructor virtual (lo que también asegura que tenga un vtable). – TrayMan

+1

indirectamente puede causar gastos indirectos de tiempo de ejecución debido al tamaño de código más grande. – rlbond

8

Se puede usar un dynamic_cast para probar tipos como se muestra a continuación:

IPlugin* iPluginPtr = NULL; 
iPluginPtr = dynamic_cast<IPlugin*>(somePluginPtr); 

if (iPluginPtr) { 
    // Cast succeeded 
} else { 
    // Cast failed 
} 
+2

Recuerde tener en cuenta que RTTI debe estar habilitado para que esto funcione. – csl

+13

Bueno, sí, en otras palabras, el lenguaje tiene que ser C++. El estándar C++ incluye RTTI. El hecho de que los compiladores le permitan apagarlo no debería ser relevante. Hacerlo es un comportamiento no estándar. Si comienza a deshabilitar partes del idioma, * por supuesto * su código dependerá de que no funcionará. También podría señalar que el código debe ser alimentado a un compilador de C++, en lugar de Fortran o C. – jalf

+1

@jalf: Ok, me ha convencido, debería ser irrelevante lo que hacen los compiladores. Pero lo hacen, así que no está de más saber lo que tendrías que hacer en la práctica. Creo que los compiladores hacen esto para que "no pagues por lo que no usas". – csl

5

Este comportamiento se denomina RTTI (Run time type information). Esta técnica es mejor evitarla, pero puede ser beneficiosa en algunas situaciones.

Hay dos formas de solucionar esto. La primera es escribir una interfaz con una función virtual pura que devuelve un código de referencia entero específico de clase. Este código se puede usar para representar un tipo específico. Estos enteros se pueden almacenar en una enumeración específica.

En las clases derivadas, puede anular el método y devolver ese tipo específico de clase. Durante el tiempo de ejecución, puede llamar a Plugin-> getType() por ejemplo, y devolverá su tipo específico. A continuación, puede realizar un static_cast en el puntero para recuperar el puntero correcto del tipo derivado.

La segunda forma es usar typeid para obtener el classtype del objeto; pero esto depende del compilador. También puedes intentar lanzar tu puntero usando dynamic_cast; dynamic_cast devuelve un puntero nulo cuando se lanza al tipo incorrecto; y uno válido cuando se lanza en un tipo correcto. El método de lanzamiento dinámico tiene una sobrecarga mayor que el método getType descrito anteriormente.

+0

Se requiere RTTI para realizar downcasting dinámico tipo seguro. No proporciona la funcionalidad "typeof" (extensión GCC) ni "auto"/"decltype" (C++ 0x). – Adisak

2

Diseñar alrededor de este problema sería la mejor opción. El buen uso de la orientación a objetos por lo general puede ayudar, pero siempre puede crear su propio sistema para consultar el tipo de un objeto utilizando una clase base que almacena un identificador para cada objeto, por ejemplo.

Siempre trate de evitar el uso de dynamic_cast, ya que con mucha frecuencia utiliza la comparación de cadenas para encontrar el tipo de objeto y eso lo hace realmente lento.

1

Boost tiene un typeof. C++ 0x no lo llama typeof, pero tiene tanto 'auto' como 'decltype' que proporcionan los mismos tipos de funcionalidad.

Dicho esto, estoy bastante seguro de que ninguno de ellos proporciona lo que realmente está buscando en este caso - a lo sumo, proporcionan solo una pequeña parte de lo que necesita/desea en general.

2

Puede usar typeof() en GCC. Con otros compiladores, o no es compatible o tiene que hacer un moldeado de plantilla loco o usar "características de error" que son muy específicas del compilador (como la forma en que Boost lo hace).

0

No respondiendo directamente al "cómo obtener typeof() en C++", pero deduzco de su pregunta que está buscando cómo hacer complementos en C++. Si ese es el caso, puede que le interese la (todavía) Boost.Extension biblioteca, y quizás en su parte reflection.

1

Seguramente solo usaría la sobrecarga?

static PluginManager::GetPlugins(Type1 &x) { 
    // Do something 
} 

static PluginManager::GetPlugins(Type2 &x) { 
    // Do something else 
} 

y luego llamar a:

PluginManager::GetPlugins(IPlugin); 
Cuestiones relacionadas