Grundlagen-Lücke in Sachen Klassendefinition
-
Hallo,
In bisherigen Anwendungen habe ich die Erfahrung gemacht, dass es für das Speichern von structs (z.B. Name, Wert) sinnvoll ist, wenn diese eine feste Größe haben ...
struct StockItem{ char m_name[20]; double m_value; }
... um sie wie folgt zu speichern ...
StockItem si; strcpy(si.m_name, "Bayer"); si.m_value = 47.11; ofstream outUP( ("Datei.dat", ios::binary); outUP.write( (char*) &si, sizeof(si) );
Nun bin ich gerade dabei einige Grundlagen-Lücken in Sachen Klassendefinition zu schließen. Dazu habe ich ein gut kommentiertes kleines Beispiel gefunden.
1 #ifndef StockItem_h 2 #define StockItem_h 1 3 4 class StockItem { 5 6 public: 7 // ctor 8 StockItem( const char* name = "", double val = 0.0); 9 10 // copy ctor 11 StockItem( const StockItem &right); 12 // dtor 13 virtual ~StockItem(); 14 // assignment operator 15 const StockItem& operator=(const StockItem &right); 16 17 // public member functions 18 virtual const char* getName() const; 19 virtual void setValue( double val); 20 virtual void setValue( const char* val); 21 virtual double getValue() const; 22 23 private: 24 // private member variables 25 char *m_name; 26 double m_value; 27 }; 28 29 #endif
Wie muss ich dieses Beispiel anpassen (Member, Initialisierungsliste), um Objekte von fester Größe zu erhalten?
By the way: Wieso finde ich bei der Suche nach 'Initialisierungsliste' keinen Eintrag. Gibt es ein sinnvolleren Suchbegriff?
Gruß
Leo
-
Wieso muss das Objekt eine feste Groesse haben?
Wenn du statt
char *m_name
wieder
char m_name[20]
nimmst hast du eine feste Groesse der Member.
-
pli schrieb:
Wieso muss das Objekt eine feste Groesse haben?
Wenn du statt
char *m_name
wieder
char m_name[20]
nimmst hast du eine feste Groesse der Member.
Das ist klar! Nicht klar ist, wie dann die Initialisierung aussehen muss.
-
Du musst nix weiter initialisieren. Durch m_name[20] wird vom Compiler automatisch dafuer gesorgt, dass du 20 byte fuer den Namen hast. Was da drin steht ist ja nicht wichtig. Im Konstruktor kannst du das ja mit memset(...) anpassen und alles mit Nullern fuellen.
StockItem::StockItem( const char *name = "", double val = 0.0 ) : m_value(val) { memset( m_name, 0, 20*sizeof(char) ); //ok, sizeof(char)==1, aber ist sauberer so strcpy( m_name, name ); }
Oder verstehe ich dich falsch? Wenn ja, dann weiss ich nicht was du fuer ein Problem meinst.
-
Oder verstehe ich dich falsch? Wenn ja, dann weiss ich nicht was du fuer ein Problem meinst.
Ja, alles bestens, danke!
Gruß
Leo
-
Es sei nicht unerwähnt, dass es nicht empfehlendswert ist dann eine Klasse (oder eine Struktur) mit
outUP.write( (char*) &si, sizeof(si) ); // Böse, böse
zu speichern. Im Allgemeinen gibt es da mannigfaltige Probleme sobald die Daten wieder eingelesen werden müssen und das einlesende Programm mit einem anderen Compiler (evtl. sogar nur einer anderen Version) oder auf einer anderen Plattform läuft. Generell (schon bei Strukturen) gibt es das Problem mit der Bytereienfolge (http://de.wikipedia.org/wiki/Endianess) und bei der genannten Klasse kommt noch (wegen der virtuellen Methoden) der vtable-Pointer dazu, der, je nach Compiler, mit in den Daten rumlümmelt. In der geschriebenen Datei hat der nix zu suchen und beim vergleichbaren Einlesen mit read() gibt es nur mit sehr viel Glück nicht heftig auf die Finger, wenn man den in der Instanz überschreibt.
Also für alles was über einfachste Tests hinausgeht besser elementweise schreiben bzw. lesen, wenn möglich (oder ein Verdacht besteht, später mal andere Plattformen unterstützen zu wollen) sogar endianess-neutral.