Frage zu Objekten, Referenzen und Vererbung
-
Also dann los:
Hier die abstrakte Basisklasse (Header + Impl.):
#ifndef MENUENTRY_H #define MENUENTRY_H #include <libraries/gadtools.h> #include <string> class MenuEntryC { friend class MenuC; friend class MenusC; public: virtual ~MenuEntryC() = 0; protected: struct NewMenu newMenu; MenuEntryC(const int type, const string label); struct NewMenu getMenuEntry(); private: MenuEntryC(); }; #endif // Implementierung #include <iostream> #include "MenuEntryC.h" MenuEntryC::MenuEntryC(const int type, const string label) { cout << "Create MenuEntry: " << this << " Label: " << label.c_str() << endl; strcpy(newMenu.nm_Label, label.c_str()); newMenu.nm_Type = type; newMenu.nm_CommKey = 0; newMenu.nm_Flags = 0; newMenu.nm_MutualExclude = 0; newMenu.nm_UserData = NULL; } MenuEntryC::~MenuEntryC() {} struct NewMenu MenuEntryC::getMenuEntry() { return newMenu; }Hier nun die erste abgeleitete Klasse (wieder mit Header und Impl.):
#ifndef MENU_H #define MENU_H #include <list> //#include "MenuC.h" #include "MenusC.h" #include "MenuEntryC.h" class MenuC : public MenuEntryC { friend class MenusC; public: MenuC(const string label, const BOOL enabled = TRUE); ~MenuC(); void addEntry(MenuEntryC *menuEntry); void printEntry(); private: list<MenuEntryC *> entries; list<MenuEntryC *>& getMenuEntries(); }; #endif // Implementierung #include "MenuC.h" MenuC::MenuC(const string label, const BOOL enabled = TRUE) : MenuEntryC(NM_TITLE, label) { cout << "Create Menu: " << getMenuEntry().nm_Label << endl; } MenuC::~MenuC() {} void MenuC::addEntry(MenuEntryC *menuEntry) { entries.push_back(menuEntry); } list<MenuEntryC *> &MenuC::getMenuEntries() { return entries; } void MenuC::printEntry() { cout << "Menu: " << this << " Label: " << this->getMenuEntry().nm_Label << endl; }Und schließlich die 2. Klasse:
#ifndef MENUITEM_H #define MENUITEM_H #include <string> #include "MenuEntryC.h" class MenuItemC : public MenuEntryC { public: MenuItemC(const string label, const BOOL enabled = TRUE); ~MenuItemC(); }; #endif // Implementierung #include "MenuItemC.h" MenuItemC::MenuItemC(const string label, BOOL enabled = TRUE) : MenuEntryC(NM_ITEM, label) { } MenuItemC::~MenuItemC() {}Im Hauptprogramm passiert dann folgendes:
MenusC menus; MenuC file("File", TRUE); file.printEntry(); // Ausgabe hier: File MenuItemC openFile("Open", TRUE); file.printEntry(); // Ausgabe hier: File MenuItemC saveFile("Save", TRUE); file.printEntry(); // Ausgabe hier: Save??? Und bei allen weiteren Ausgaben auch!!!Alle Ausgaben erfolgen mit der ObjektID von file!
Ich hab keine Ahnung was hier los ist???!?
-
die definition von NewMenu fehlt noch (und ich bin ziemlich sicher, dass der fehler dort liegt - die symptome deuten in eine bestimmte richtung).
-
NewMenu ist eine Struktur des Betriebssystems und dessen API, sie ist in der libraries/gadtools.h definiert:
struct NewMenu { UBYTE nm_Type; STRPTR nm_Label; STRPTR nm_CommKey; UWORD nm_Flags; LONG nm_MutualExclude; APTR nm_UserData; };Wenn gewünscht kann ich auch noch die Beschreibung der Einträge liefern.
-
und STRPTR ist ein pointer auf char?
-
Soweit ich weiss, ja.
-
dann liegt hier jede menge undefiniertes verhalten vor.
MenuEntryC::MenuEntryC(const int type, const string label) { cout << "Create MenuEntry: " << this << " Label: " << label.c_str() << endl; strcpy(newMenu.nm_Label, label.c_str()); newMenu.nm_Type = type; newMenu.nm_CommKey = 0; newMenu.nm_Flags = 0; newMenu.nm_MutualExclude = 0; newMenu.nm_UserData = NULL; }hier wird nm_label nicht initialisiert - das strcpy schreibt also irgendwo hin.
-
In allen C-Programmbeispielen, die systemkonform programmiert wurden, werden die Arrays aus struct NewMenu wie folgt angelegt:
struct NewMenu gb_MenuDescribe[] = { { NM_TITLE, "Project", NULL, 0, 0, NULL }, { NM_ITEM, "Quit", NULL, 0, 0, NULL }, { NM_END, NULL, NULL, 0, 0, NULL } };Ich versuche hier eine etwas dynamischere Variante. Im Bsp. hier werden die STRPTR doch auch nirgends initialisiert? Oder wird hierbei der STRPTR auf den Anfang der jeweils übergebenen Zeichenkette gelegt? Dann hab ich aber wieder das Problem aus meinem anderen Post, dass ich eine Struktur nicht in der Initialisierungsliste des CTors initialisieren kann!
-
Reth schrieb:
In allen C-Programmbeispielen, die systemkonform programmiert wurden, werden die Arrays aus struct NewMenu wie folgt angelegt:
struct NewMenu gb_MenuDescribe[] = { { NM_TITLE, "Project", NULL, 0, 0, NULL }, { NM_ITEM, "Quit", NULL, 0, 0, NULL }, { NM_END, NULL, NULL, 0, 0, NULL } };Ich versuche hier eine etwas dynamischere Variante. Im Bsp. hier werden die STRPTR doch auch nirgends initialisiert?
Oder wird hierbei der STRPTR auf den Anfang der jeweils übergebenen Zeichenkette gelegt?
korrekt. der typ eines stringliterals ist ein zeiger auf ein konstansten char, der auf die zeichenkette zeigt.
Dann hab ich aber wieder das Problem aus meinem anderen Post, dass ich eine Struktur nicht in der Initialisierungsliste des CTors initialisieren kann!
das musst du ja hier auch nicht tun. und du tust es ja bereits auch für die anderen member von NewMenu nicht. an nm_Label ist nichts besonderes, das dich hindert, ihm auf die selbe weise einen wert zuzuweisen.
-
Hi, danke hast recht.
Ist mir gestern auch noch eingefallen, sollte dann ca. so funktionieren:
newMenu.nm_Label = &(label.c_str()[0]);Wenn ich die Definition von c_str() noch korrekt im Kopf hab.
-
Dir ist schon klar, daß das von label.c_str() zurückgegebene char-Array höchstens so lange existiert wie das label-Objekt, ja? Spätestens wenn du newMenu nach der Destruktion von label verwendest, hast du ein Problem (wohlmöglich sogar deutlich früher).
-
Ja, da ich das Label aber mit:
MenuC file("File", TRUE);im Hauptprogramm anlege, sollte es doch so lange existieren, bis file out of scope geht, oder nicht?
Evtl. wäre es hier noch besser, wenn ich den Labelstring per Referenz übergebe, statt per Copy.
Ciao
-
Der Text existiert solange bis das temporäre Objekt string( "File" ) out of scope geht. Das ist aber nach dem Semikolon in dieser Zeile. Ab diesem Zeitpunkt ist in einer Struktur tief in der API ein ungültiger Zeiger abgelegt.
-
Hm, das kapier ich jetzt nicht ganz, da das Objekt, welches mit:
MenuC file("File", TRUE);angelegt wird doch so lange existiert, bis der umgebende Scope (Methode etc.) verlassen wird? Dachte ich zumindest? Oder nicht?
-
Das Objekt file ja, der String, der aus dem Literal "File" erzeugt wird, nicht.
Was erwartet der File-Konstruktor? Ein std::string.
Was gibst Du ihm? Ein const char*.Was passiert? Der Compiler entdeckt eine implizite Umwandlung von const char* nach string, bei der der Text kopiert wird. Der Konstruktor von MenuEntryC bekommt einen konstanten std::string, aus dem Du c_str() benutzt. Danach ist der Konstruktor beendet, der konstante std::string, der gebraucht wurde um const char* an MenuEntryC zu übergeben wird gelöscht, und Du stehst da mit einem Pointer, der aus einem c_str() eines jetzt nicht mehr gültigen Objektes stammt.
-
Wie kann ich dann in diesem Fall den String richtig initialisieren, damit er dauerhaft erhalten bleibt, bis file out of scope geht?
-
Übergib doch einfach direkt ein "const char*":
MenuEntryC::MenuEntryC(const int type, const char* pLabel) { cout << "Create MenuEntry: " << this << " Label: " << pLabel << endl; newMenu.nm_Label = pLabel; newMenu.nm_Type = type; newMenu.nm_CommKey = 0; newMenu.nm_Flags = 0; newMenu.nm_MutualExclude = 0; newMenu.nm_UserData = NULL; }Edit: bei den abgeleiteten Klassen (z.B. MenuC) dann natürlich auch...
-
Das geht natürlich auch, wollte aber möglichst mit C++/STL-Konstrukten arbeiten,
wobei der const char* hier bestimmt performanter ist, mich aber immer an C erinnert.Aber ich muss mich wohl damit abfinden, dass die Gemeinsamkeiten zw. C und C++ wohl größer sind als mir lieb wäre. Ich wäre in C++ auch gern ohne Zeiger ausgekommen, aber dann mutieren die STL-Container ja zu Speichermonstern, da immer kopiert wird.
Ciao
-
Nur der Vollständigkeit halber:
const char * hat nicht funktioniert, da STRPTR ein char * ist.
Nachdem ich die Parameter in char * geändert habe, hats bestens funktioniert.
-
Trotzdem würde ich die Parameter als "const char *" übergeben und nur an der entsprechenden Zuweisung einen cast vornehmen:
newMenu.nm_Label = const_cast<char *>(pLabel); // bzw <STRPTR>
-
Danke, werde ich probieren!
Da fehlt mir halt die Erfahrung mit C++. Dachte der const_cast geht nur in die andere Richtung (also wenn ich was konstant machen will, was bisher noch nicht als konstant deklariert war).