Pregunta

¿Hay alguna forma de agregar un campo a una clase en tiempo de ejecución (un campo que no existía antes)? Algo como este fragmento:

Myobject *ob; // create an object
ob->addField("newField",44); // we add the field to the class and we assign an initial value to it
printf("%d",ob->newField); // now we can access that field

Realmente no me importa cómo se haría, no me importa si es un truco feo o no, me gustaría saber si podría hacerse, y un pequeño ejemplo, si es posible.

Otro ejemplo: dice que tengo un archivo XML que describe esta clase:

<class name="MyClass">
   <member name="field1" />
   <member name="field2" />
</class>

y quiero " agregar " los campos " campo1 " y " campo2 " a la clase (asumiendo que la clase ya existe). Digamos que este es el código para la clase:

class MyClass {
};

No quiero crear una clase en tiempo de ejecución, solo quiero agregar miembros / campos a una existente.

¡Gracias!

¿Fue útil?

Solución

Usa un mapa y una variante.

Por ejemplo, usando la variante boost ::. Ver http://www.boost.org/doc/libs/ 1_36_0 / doc / html / variant.html

(Pero, por supuesto, puede crear el suyo propio, para adaptarse a los tipos de sus atributos XML).

#include <map>
#include <boost/variant.hpp>

typedef boost::variant< int, std::string > MyValue ;
typedef std::map<std::string, MyValue> MyValueMap ;

Al agregar MyValueMap como miembro de su clase, puede agregar propiedades de acuerdo con sus nombres. Lo que significa el código:

oMyValueMap.insert(std::make_pair("newField", 44)) ;
oMyValueMap.insert(std::make_pair("newField2", "Hello World")) ;
std::cout << oMyValueMap["newField"] ;
std::cout << oMyValueMap["newField2"] ;

Al encapsularlo en una clase MyObject y agregar los accesos sobrecargados correctos en esta clase MyObject, el código anterior se vuelve algo más claro:

oMyObject.addField("newField", 44) ;
oMyObject.addField("newField2", "Hello World") ;
std::cout << oMyObject["newField"] ;
std::cout << oMyObject["newField2"] ;

Pero pierde algo la seguridad de tipo de C ++ al hacerlo. Pero para XML, esto es inevitable, supongo.

Otros consejos

No hay forma de hacerlo de la manera que has descrito, ya que el compilador debe resolver la referencia en el momento de la compilación, generará un error.

Pero vea El patrón de diseño universal .

No puede hacer que la sintaxis funcione (debido a la comprobación estática en el momento de la compilación), pero si está dispuesto a modificar la sintaxis, puede lograr el mismo efecto con bastante facilidad. Sería bastante fácil tener un miembro del diccionario con una asignación de cadena > blob, y tener funciones miembro como:

template< typename T > T get_member( string name );
template< typename T > void set_member( string name, T value );

Puede hacer que la sintaxis sea más compacta / complicada si lo desea (p. ej., mediante el uso de una anulación de operador '- >'). También hay algunos trucos específicos del compilador que podría aprovechar (MSVC admite __declspec (propiedad), por ejemplo, que le permite asignar referencias a una variable miembro a métodos de un formato específico). Sin embargo, al final del día, no podrás hacer algo que el compilador no acepta en el idioma y compilar.

Versión corta: No puedo hacerlo. No hay soporte nativo para esto, c ++ está tipado estáticamente y el compilador tiene que conocer la estructura de cada objeto a manipular.

Recomendación: Use un intérprete incorporado. Y no escriba su propia cuenta (vea a continuación), obtenga una que ya esté funcionando y esté depurada.


Qué puede hacer: Implemente el intérprete suficiente para sus necesidades.

Sería lo suficientemente simple como para configurar la clase con un miembro de datos como

std::vector<void*> extra_data;

a la que podría adjuntar datos arbitrarios en tiempo de ejecución. El costo de esto es que tendrá que administrar esos datos a mano con métodos como:

size_t add_data_link(void *p); // points to existing data, returns index
size_t add_data_copy(void *p, size_t s) // copies data (dispose at
                                        // destruction time!), returns 
                                        // index 
void* get_data(size_t i); //...

Pero ese no es el límite, con un poco más de cuidado, puede asociar los datos arbitrarios con un nombre y puede continuar elaborando este esquema todo lo que desee (agregue información de tipo, etc.), pero Todo esto se reduce a implementar un intérprete para cuidar su flexibilidad en el tiempo de ejecución.

No - C ++ no admite ninguna manipulación del sistema de tipos como esta. Incluso los idiomas con cierto grado de reflexión en tiempo de ejecución (por ejemplo, .NET) no admitirían exactamente este paradigma. Necesitarías un lenguaje mucho más dinámico para poder hacerlo.

Estaba mirando esto e hice una pequeña búsqueda, este fragmento de código se obtuvo de: Blog de Michael Hammer parece ser una buena manera de hacerlo, utilizando boost :: cualquier

Primero, define una estructura que define un std :: map que contiene una clave (es decir, el nombre de la variable) y el valor. Se define una función para indicar el par y establecerla junto con una función para obtener el valor. Bastante simple si me preguntas, pero parece una buena manera de comenzar antes de hacer cosas más complejas.

struct AnyMap {
  void addAnyPair( const std::string& key , boost::any& value );

  template<typename T>
  T& get( const std::string key ) {
    return( boost::any_cast<T&>(map_[key]) );
  }

  std::map<const std::string, boost::any> map_;
};

void AnyMap::addAnyPair( const std::string& key , boost::any& value ) {
  map_.insert( std::make_pair( key, value ) );
}

En pocas palabras, esto es un truco, ya que C ++ es un lenguaje estricto de comprobación de tipos, y por lo tanto, el monstruo está dentro de los que cumplen las reglas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top