Frage

Gibt es eine Möglichkeit, ein Feld zu einer Klasse zur Laufzeit (ein Feld, das es vorher nicht gab) hinzufügen? So etwas wie dieses Snippet:

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

ich nicht wirklich egal, wie es getan werden würde, es ist mir egal, ob es ein hässlicher Hack ist oder nicht, ich würde gerne wissen, ob es getan werden könnte, und ein kleines Beispiel, wenn möglich.

Ein weiteres Beispiel: sagen, ich habe eine XML-Datei, diese Klasse zu beschreiben:

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

, und ich mag die Felder „Feld1“ und „Feld2“ die Klasse „add“ (vorausgesetzt, die Klasse ist bereits vorhanden). Lassen Sie uns sagen, dass dies der Code für die Klasse ist:

class MyClass {
};

Ich will nicht eine Klasse zur Laufzeit erstellen, ich mag nur Mitglieder / Felder zu einem bestehenden hinzufügen.

Danke!

War es hilfreich?

Lösung

Verwenden Sie eine Karte und eine Variante.

Zum Beispiel mit boost :: Variante. Siehe http://www.boost.org/doc/libs/ 1_36_0 / doc / html / variant.html

(Aber natürlich können Sie Ihre eigenen erstellen, die Typen von XML-Attribute anpassen.)

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

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

Mit dem MyValueMap als Mitglied der Klasse hinzufügen, können Sie Eigenschaften hinzufügen ihre Namen nach. Was bedeutet, den Code:

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

es in einer MyObject-Klasse Durch Einkapseln, und das Hinzufügen der richtigen überlasteten Accessoren in dieser MyObject-Klasse, vor dem Code wird etwas deutlicher:

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

Aber Sie verlieren etwas die Art Sicherheit von C ++ dabei. Aber für XML, das ist unvermeidlich, denke ich.

Andere Tipps

Es gibt keinen Weg, um es in der Art und Weise zu tun, die Sie beschrieben haben, da der Compiler die Referenz bei der Kompilierung auflösen muss -. Es wird ein Fehler generiert

Aber finden Sie unter The Universal Design Pattern .

Sie können nicht, dass die Syntax Arbeit machen (wegen der statischen Prüfung bei der Kompilierung), aber wenn Sie bereit sind, um die Syntax zu ändern, können Sie den gleichen Effekt ziemlich leicht zu erreichen. Es wäre ziemlich einfach, ein Wörterbuch Element mit einem String-> Blob-Mapping zu haben, und hat Member-Funktionen wie:

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

Sie können die Syntax kompaktere / heikel machen, wenn Sie wollen (zB: mit einem ‚->‘ Operator überschreiben). Es gibt auch einige Compiler-spezifische Tricks, die Sie könnte möglicherweise Hebelwirkung (MSVC unterstützt __declspec (Eigenschaft), zum Beispiel, die Sie Verweise auf eine Membervariable Methoden eines bestimmten Formats zur Karte erlaubt). Am Ende des Tages, aber du wirst in der Lage sein, etwas zu tun nicht der Compiler nicht in der Sprache akzeptiert und bekommt es zu kompilieren.

Kurzversion: Kann es nicht tun. Es gibt keine native Unterstützung für das ist, c ++ ist statisch typisiert und die Compiler hat die Struktur jedes Objekt zu wissen, manipuliert werden.

Empfehlung: Verwenden Sie ein eingebettetes interperter. Und schreiben Sie nicht Ihre eigene (siehe unten), erhalten eine, die bereits arbeitet und ausgetestet.


Was Sie tun können. Implementieren Sie gerade genug interperter für Ihre Bedürfnisse

Es wäre Setup einfach genug sein, die Klasse mit einem Datenelement wie

std::vector<void*> extra_data;

, auf die kann man beliebige Daten zur Laufzeit anhängen. Die Kosten hierfür sind, dass Sie diese Daten von Hand mit Methoden wie verwalten müssen:

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

Aber das ist nicht die Grenze, mit ein wenig mehr Sorgfalt, um die beliebige Daten mit einem Namen zuordnen konnte und Sie können weiterhin diese Regelung erarbeiten, so weit, wie Sie wollen (Typ Info hinzufügen, etc ...), aber was das kommt darauf an, ein interperter Umsetzung Ihrer Laufzeit Flexibilität zu sorgen.

Nein - C ++ keine Manipulation des Typs System wie dieses unterstützen. Auch Sprachen mit einer gewissen Laufzeit Reflexion (z .NET) nicht genau dieses Paradigma unterstützen. Sie müssten eine viel dynamischere Sprache der Lage sein, es zu tun.

Ich war an diesem suchen und ich habe ein wenig suchen um diese Code-Schnipsel, erhalten aus: Michael Hammer Blog scheint ein guter Weg, dies zu tun, von boost :: jede

Zuerst definieren Sie eine Struktur, die einen std :: map definiert, die einen Schlüssel enthält (das heißt Variablenname) und den Wert. Eine Funktion wird auf Anzeige definiert das Paar und legen Sie es mit einer Funktion entlang den Wert zu erhalten. Ganz einfach, wenn Sie mich fragen, aber es scheint einen guten Weg zu beginnen, bevor komplexere Dinge zu tun.

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 ) );
}

Unterm Strich ist dies ein Hack, da C ++ strenge Typprüfung Sprache ist, und somit Monster liegen in für diejenigen, die die Regeln beugen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top