2010-02-12 13 views
7

Estoy pensando en agregar algún tipo de capacidades de reflexión a algunas clases de C++ (para no tener que usar RTTI): obtener nombres de métodos, campos declarados, nombre de clase ... este tipo de cosas.¿Cómo implementaría la reflexión básica en C++?

Estaba pensando en analizar los archivos fuente existentes, obtener una lista de los campos declarados & métodos, y volver a escribir cada archivo fuente, agregando este tipo de información a cada clase.

¿Qué opina de este enfoque? Me gustaría hacer todo desde cero, ya que creo que es una gran oportunidad para aprender. ¿Sugerirías otras formas de hacer esto?

// OFFTOPIC: ¿así es como lo hace Qt?

+0

¿No costará esto más que RTTI, entonces, qué gana esto? – Mark

+0

Tough. No puede ordenar el compilador para generar los metadatos que necesita del código fuente. RTTI es extremadamente inadecuado. Tendrá que escribir su propio analizador de lenguaje C++. Eso se ha hecho ... –

+0

@nobugz: Claro, la gente ha escrito sus propios analizadores de C++. Eso está muy lejos de ser trivial. C++ es, muy simplemente, un verdadero dolor para analizar. –

Respuesta

1

A menos que desee modificar el compilador de C++ o depender de las extensiones del proveedor, necesitará un montón de macros de CPP que construyan estructuras de datos.

3

Compruebe la biblioteca Boost.Mirror. Aún no se ha aceptado en Boost, por lo que tendrá que llamar al download it de Boost Vault.

La biblioteca aún está en desarrollo y los documentos son escasos, pero al estudiar provided examples puede lograr lo que desea.

EDIT: si realmente desea analizar su propio código C++ entonces tal vez debería considerar clang

+0

Wow. Se ve tan conciso y fácil de usar. – Eric

+0

¿Estás siendo sarcástico? – Manuel

+2

print_meta_data Eric

3

Me tenedor gcc.

2

Sí, así es como lo hace Qt, excepto que no agrega la información a la clase en sí, sino que crea una nueva clase llamada metaclass que contiene datos estáticos sobre la clase. Esto es mejor por razones obvias.

Ningún enfoque pure-C++ proporcionará una reflexión completamente automática, el lenguaje no lo permite. Hay muchos intentos, incluidos Boost.Mirror y Boost.Reflection, pero todos requieren adiciones repetidas a su fuente.

0

Tal vez pueda usar la biblioteca typeinfo, con ella ahora puede obtener una clase de objeto en tiempo de ejecución. Ejemplo:

#include<iostream> 

#include<typeinfo> 
class A{}; 

int main() 
{ 
A a; 

std::cout<<typeid(a).name(); 

} 

Puede ver más en: http://www.cplusplus.com/reference/std/typeinfo/

[] `s

+0

No quiero usar RTTI. – Geo

1

Usted puede encontrar gccxml digno de una mirada. Por ejemplo, convertirá this en this, lo que significa que solo tiene que analizar XML en lugar de C++.

Hay una interesante SP & E paper que describe el uso de gccxml en conjunción con un engarce modificado para "proporcionar la funcionalidad de Java-reflexión similar a las aplicaciones C++ de una manera limpia y no intrusiva".

1

Modifique el compilador para producir un método GetClass estático, devolviendo un puntero a un objeto Class que describa la clase, para cada clase definida.

Modifique el compilador/enlazador para extraer los metadatos necesarios y rellene los que están en secciones/símbolos especiales de la imagen ejecutable resultante, al igual que se agregan los símbolos de depuración.

GetClass usaría (leer/cargar/almacenar en caché?) Los metadatos anteriores.

Y sí. Eso es mucho trabajo. (Y un buen efecto secundario es que casi te lleva a eliminar los archivos de encabezado, ya que esa información ahora se puede extraer de una imagen)

1

C++ no admite la reflexión. Los esfuerzos de boost y RTTI son bastante limitados y medio cocidos. yo no los recomendaria a ellos.

Mencionaste que puedes comenzar desde scatch. Bueno, puedes escribir un lector de C++ usando lex/yacc, o ANTLR. Mucho trabajo, pero aprenderás mucho.

Si escribir un analizador es una tarea formidable para ti, existen otras opciones para obtener metadatos de una clase. Microsoft tiene DIA SDK que proporciona información de símbolos. Doxygen puede generar archivos XML que puede analizar para obtener los nombres de los campos de una clase. Tuve cierto éxito en el análisis de archivos XML de doxygen.

Si solo trabaja con la plataforma de Microsoft, una solución viable es usar la biblioteca de tipos (TLB). Requiere convertir la clase en una interfaz en MS IDL. MIDL compila el IDL en .tlb, y su aplicación puede cargar el archivo .tlb en tiempo de ejecución. Su aplicación puede obtener casi toda la información sobre la clase a través de la interfaz, las propiedades y los métodos de ITypeInfo.

+0

¡Guau! ¡Doxygen ni siquiera pasó por mi mente! ¡Enfria uno! – Geo

1

Siga la décima ley de Greenspun y ya está listo: simplemente implemente una implementación ad hoc, informalmente especificada, llena de errores y lenta de la mitad de Common Lisp. Elija un medio que respalde la implementación de la reflexión. :)

O, aquí está una idea:

Encienda archivos de mapas (y, posiblemente, la generación de montaje) en su construcción. Implemente una aplicación que genere código para crear una biblioteca dinámica. Debería poder obtener toda la información estática (nombres de métodos, parámetros, tipos, etc.) sobre las clases de la fuente o uno de los artefactos de construcción. Al usar el mapa o el ensamblaje, podrá encontrar direcciones de funciones, compensaciones de punteros de funciones virtuales, direcciones de variables globales, compensaciones de variables, información sobre variables asignadas de pila y registro, etc., etc. A partir de esta información construya una biblioteca que contenga las llamadas para obtener toda esta información pasando nombres de tipos, punteros, nombres de funciones, etc.

Ahora, en C++, escriba una biblioteca que contenga funciones y macros que le permitan poner identificaciones únicas que lo harán compilarse en el código para identificar los inicios de funciones, todas las llamadas de reflexión, compensación de EIP tras llamadas de reflexión, etc. Utilice macros de ensamblaje en línea en ubicaciones apropiadas que dejen espacio donde sea necesario con NOPs para poner algunas instrucciones si es necesario, generalmente justo después de CARNÉ DE IDENTIDAD. Además, proporcione funciones de biblioteca de puente que permitan que la funcionalidad de reflexión controle lo que puede alinearse (por ejemplo, obtener la dirección de una función) o tener que realizar llamadas a la biblioteca dinámica incorporada en el paso posterior a la construcción.

Finalmente, escriba un enlazador de reflexión posterior a la compilación. Sugiero "kniltsoPostlink", pero eso depende de usted. En esta etapa de búsqueda de sus identificaciones únicas (¿mencioné para facilitarlo, probablemente debería hacer los ID GUID para que pueda buscarlos en el binario?) Y, donde sea que el ID esté marcando una llamada de reflexión a una función, o una definición de una clase, etc., coloque suficiente información allí (en un formato que pueda determinar fácilmente justo a tiempo al escribir la biblioteca del reflector) y luego en la ID antes de una llamada a la biblioteca del reflector, vuelva a escribir la llamada para que extrae los parámetros que necesita de esos bits de datos, o simplemente coloca los bits de datos allí donde corresponda, no puedo saberlo de antemano, pero a medida que lo escribe, estos pequeños detalles se le aparecerán.

De todos modos, sé que no he dado mucho código, y de hecho tengo la intención de iniciar un proyecto sobre esto en algún momento una vez que tenga suficiente tiempo libre. Quiero decir, cada pequeña parte debería ser muy simple, así que a medida que lo haces de forma incremental, cada pequeña pieza debería quedar clara siempre y cuando sigas las pautas establecidas aquí. Es posible que parte de esto sea incluso más simple de lo que he descrito aquí, porque este fue el peor de los casos. Incluso puede escaparse sin tener que volver a escribir el código en las llamadas reflector; simplemente colocar los datos en los lugares apropiados puede permitir que la biblioteca los extraiga cuando los necesita sin más información.

Estoy muy contento de que haya preguntado; Estoy muy ocupado ahora, pero si tienes una noche gratis, imagino que será un buen comienzo en una primera versión, y estaré encantado de lanzar lo antes posible.

;)

+0

Guau, veo que ha pasado un año y medio desde que hizo esta pregunta, lamento que haya tenido que irse sin una respuesta real durante tanto tiempo, pero es bueno saber que podría ayudar. : D ♡ – shelleybutterfly

+0

Muy interesante y muy detallado. Voy a leer un poco sobre eso. ¡Gracias! – Geo

+0

bueno, de nada. :) tenga en cuenta que, aunque realmente creo que esto puede funcionar, solo es una hoja de ruta. (Los comentarios sobre lo fácil que sería, en otras palabras, son irónicos). Pero sí creo que, abordados de forma iterativa para encontrar la mejor solución, se puede hacer. (Tampoco estoy tan seguro de que esto sea más fácil que escribir una extensión a C++ y extender gcc para compilarla.) ... Suena un poco divertido como lo describí, algo así como: olvidarte C++, estás reflejándose ya sea que te guste o no ... :) – shelleybutterfly

Cuestiones relacionadas