2009-05-12 13 views
12

He estado trabajando durante años con Java. Durante esos años, hice un uso extenso (o tal vez solo frecuente) de la reflexión, y la encontré útil y agradable. Pero hace 8 meses cambié mi trabajo, y ahora Java es solo un recuerdo, y estoy obteniendo mis manos de C++. Entonces ahora me pregunto si hay algún mecanismo de reflexión en C++. He leído sobre RTTI, pero siento que no es de ninguna manera el poder de la reflecion de Java (u otros idiomas). Estoy empezando a pensar que no hay forma de hacer esto en C++. ¿Me equivoco?Reflexión en C++

Respuesta

5

Si está buscando una manera totalmente general, para manipular objetos en tiempo de ejecución cuando no se sabe sus tipos en tiempo de compilación en C++, debe esencialmente a:

  1. definir una interfaz (clase base abstracta con todos los métodos virtuales puros y sin miembros) para cada capacidad que una clase pueda admitir.
  2. Cada clase debe heredar virtualmente de todas las interfaces que quiere implementar (posiblemente entre otras clases).

Ahora, supongamos pFoo mantiene un puntero de interfaz de tipo IFoo* a algún objeto x (que no es necesario conocer el tipo concreto x 's). Se puede ver si este objeto soporta la interfaz IBar diciendo:

if (IBar* pBar = dynamic_cast<IBar*>(pFoo)) { 
    // Do stuff using pBar here 
    pBar->endWorldHunger(); 
} else { 
    // Object doesn't support the interface: degrade gracefully 
    pFoo->grinStupidly(); 
} 

Este enfoque asume que conoce todas las interfaces pertinentes en tiempo de compilación - si no lo hace, usted no será capaz de utilizar C++ normales sintaxis para llamar a los métodos de todos modos. Pero es difícil imaginar una situación en la que el programa que llama no sepa qué interfaces necesita, sobre el único caso que puedo pensar sería si desea exponer objetos C++ a través de un intérprete interactivo. Incluso entonces, puede idear una forma (fea, de mantenimiento intensivo) de calzar esto en el paradigma anterior, de modo que los métodos se puedan llamar especificando sus nombres y argumentos como cadenas.

El otro aspecto a considerar es la creación de objetos . Para lograr esto sin conocer tipos concretos, necesitará una función de fábrica, además de identificadores únicos para clases para especificar qué clase concreta desea. Es posible hacer arreglos para que las clases se registren en una fábrica global al inicio, as described here by C++ expert Herb Sutter - esto evita mantener una declaración gigantesca switch, facilitando considerablemente el mantenimiento. Es posible usar una sola fábrica, aunque esto implica que hay una sola interfaz que cada objeto en su sistema debe implementar (la fábrica devolverá un puntero o referencia a este tipo de interfaz).

Al final del día, lo que terminan con es básicamente (isomorfo a) COM-dynamic_cast<IFoo*> hace el mismo trabajo que QueryInterface(IID_IFoo), y la interfaz de base aplicado por todos los objetos es equivalente a IUnknown.

1

RTTI es una solución (¿qué parte de Java crees que no está en RTTI?); De lo contrario, puedes implementar tu propia estructura de objetos; deja que cada objeto C++ herede alguna interfaz de reflexión y luego debería funcionar.

+1

Creo que mi conocimiento sobre RTTI es pobre ... pero ¿hay alguna manera de obtener una lista de métodos o atributos de un objeto usando RTTI? – aitor

+2

@aitor: No, no lo creo. RTTI puede indicarle el tipo de objeto en tiempo de ejecución, pero es su responsabilidad convertir esta información en información más precisa, como la disponibilidad de métodos y atributos. –

+1

El complejo RTTI puede verse así: http://www.codeproject.com/KB/library/vcf_rtti.aspx – Francis

15

Dado que el estándar C++ no cubre el concepto de "metadatos", no hay ningún método portátil (a través de diferentes compiladores y plataformas) para la reflexión en tiempo de ejecución que no sea el RTTI que usted ya mencionó.

En C++, también hay una posibilidad de reflexión en tiempo de compilación (piense en boost::type_traits y boost::type_of), pero es limitado en comparación con, digamos, Nemerle o LISP.

La mayoría de los marcos principales (MFC, Qt, etc.) le permiten extraer metainformación en tiempo de ejecución, pero requieren todo tipo de anotaciones especiales para que funcione (ver RUNTIME_CLASS y otros como ejemplo).

0

si todo lo que está usando es una inyección de dependencia (una implementación de alguna interfaz^H^H^H^H^H^clase abstracta pura), puede intentar la carga dinámica de archivos .dll o .so que contienen la implementación del día para lo que sea que sea el complemento.

Probablemente solo se agarre a las pajas, ya que esto no funcionará bien para múltiples implementaciones de cosas al mismo tiempo.

3

Debe utilizar el patrón de visitante. Cualquier clase en la que pueda reflejarse necesitaría heredar una clase base que le otorgara una función de miembro Reflect, que aceptaría una clase de visitante. Luego, la función Reflect pasará información o capacidades sobre los otros miembros al visitante.

Muchas bibliotecas populares utilizan este patrón para casos específicos; por ejemplo, la función Serialize en MFC hace esto, pero específicamente para la serialización.

Probablemente pueda diseñar un sistema de tal manera que el visitante pueda hacer llamadas dinámicas a funciones miembro, obtener o establecer los valores de los miembros de datos, etc. Pero sería responsabilidad de cada clase mantener una función Reflect escrita a mano, que sería una repetición de la estructura de la clase.

1

La reflexión es el proceso mediante el cual un programa de computadora puede observar y modificar su propia estructura y comportamiento. No veo cómo se puede hacer la reflexión en C++. RTTI es útil solo para el tipo de datos del objeto en la memoria en tiempo de ejecución.

4

Echa un vistazo a my answer to a similar question. Ambas soluciones (XRTTI y OpenC++) propuestas se basan en herramientas externas que generan los metadatos de reflexión para usted durante el proceso de compilación.

0

¿Qué necesitas hacer en C++ y con qué plataforma estás trabajando? Conozco una forma de obtener las definiciones de clases completas y las funciones de invocación utilizando estos datos, funciona en Windows pero no sé sobre otras plataformas. La idea es tomar datos de la tabla de exportación DLL o exe. No es fácil, nos tomó varios meses de trabajo conseguir una implementación decente, pero hará todo lo que hacen los lenguajes de soporte de la reflexión.

+0

¿Qué significa tu respuesta? ¿De dónde es la implementación decente de la que hablas? –

Cuestiones relacionadas