Question

Existe-t-il un moyen d'ajouter un champ à une classe au moment de l'exécution (un champ qui n'existait pas auparavant)? Quelque chose comme cet extrait:

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

Je ne me soucie pas vraiment de savoir comment cela serait fait, peu importe que ce soit un vilain coup ou pas, je voudrais savoir si cela peut être fait, et un petit exemple, si possible.

Autre exemple: , disons que j'ai un fichier XML décrivant cette classe:

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

et je souhaite " ajouter " les champs " champ1 " et " field2 " à la classe (en supposant que la classe existe déjà). Disons que ceci est le code de la classe:

class MyClass {
};

Je ne veux pas créer de classe au moment de l'exécution, je veux simplement ajouter des membres / champs à une classe existante.

Merci!

Était-ce utile?

La solution

Utilisez une carte et une variante.

Par exemple, utilisez boost :: variant. Voir http://www.boost.org/doc/libs/ 1_36_0 / doc / html / variant.html

(Mais bien sûr, vous pouvez créer le vôtre, en fonction des types d'attributs XML.)

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

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

En ajoutant MyValueMap en tant que membre de votre classe, vous pouvez ajouter des propriétés en fonction de leurs noms. Ce qui signifie le code:

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

En l'encapsulant dans une classe MyObject et en ajoutant les accesseurs surchargés de droite dans cette classe MyObject, le code ci-dessus devient un peu plus clair:

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

Mais vous perdez quelque peu la sécurité de type du C ++. Mais pour XML, c’est inévitable, je suppose.

Autres conseils

Il n'y a aucun moyen de le faire comme vous l'avez décrit, car le compilateur doit résoudre la référence au moment de la compilation - cela générera une erreur.

Mais consultez Le modèle de conception universel .

Vous ne pouvez pas utiliser cette syntaxe (à cause de la vérification statique au moment de la compilation), mais si vous souhaitez modifier la syntaxe, vous pouvez obtenir le même effet assez facilement. Il serait assez facile d'avoir un membre du dictionnaire avec un mappage de chaînes de caractères > et des fonctions de membre telles que:

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

Vous pouvez rendre la syntaxe plus compacte / plus délicate si vous le souhaitez (par exemple: en utilisant un remplacement d'opérateur '- >'). Il existe également des astuces spécifiques au compilateur que vous pouvez éventuellement exploiter (MSVC prend en charge __declspec (propriété), par exemple, ce qui vous permet de mapper les références d'une variable membre à des méthodes d'un format spécifique). En fin de compte, cependant, vous ne pourrez pas faire quelque chose que le compilateur n'accepte pas dans le langage et le faire compiler.

Version abrégée: Impossible de le faire. Il n’ya pas de support natif pour cela, c ++ est typé de manière statique et le compilateur doit connaître la structure de chaque objet à manipuler.

Recommandation : utilisez un interpréteur incorporé. Et n’écrivez pas le vôtre (voir ci-dessous), prenez-en un qui fonctionne déjà et qui est débogué.

Ce que vous pouvez faire: implémentez juste assez d'interperter pour vos besoins.

Il serait assez simple de configurer la classe avec un membre de données tel que

std::vector<void*> extra_data;

auquel vous pouvez attacher des données arbitraires au moment de l'exécution. Le coût de ceci est que vous devrez gérer ces données à la main avec des méthodes telles que:

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

Mais ce n’est pas la limite, avec un peu plus de soin, vous pouvez associer les données arbitraires à un nom et continuer à élaborer ce schéma aussi loin que vous le souhaitez (ajoutez des informations de type, etc.), mais cela revient à mettre en place un interperter pour prendre en charge votre flexibilité d'exécution.

Non - C ++ ne prend en charge aucune manipulation du système de types de ce type. Même les langues avec un certain degré de réflexion à l'exécution (par exemple .NET) ne prendraient pas en charge exactement ce paradigme. Vous aurez besoin d’un langage beaucoup plus dynamique pour pouvoir le faire.

Je regardais ceci et j’ai fait une petite recherche autour de cet extrait de code obtenu à partir de: Le blog de Michael Hammer semble être un bon moyen d’y parvenir en utilisant boost :: tout

Vous définissez d’abord une structure qui définit un std :: map contenant une clé (nom de variable) et la valeur. Une fonction est définie pour ajouter la paire et la définir avec une fonction pour obtenir la valeur. C'est assez simple si vous me le demandez, mais cela semble un bon moyen de commencer avant de faire des choses plus complexes.

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 bout de ligne, il s’agit d’un hack, car C ++ est un langage de vérification de type strict, et donc monster est à l’intérieur de ceux qui respectent les règles.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top