Multidimensionale Menüstruktur mit OOP und stl::vector
-
das erste Listing von mir war lauffähig und bezogen auf seinen Schwierigkeitsgrad nicht unbedingt trivial. Und - wunderbar - mit dem Punkt Operator funktioniert der Zugriff auf die statische Instanz. Dafür wieder mal dickes Dankeschön.
Ich möchte noch meine Zweifel anmelden, dass man nicht ohne teure Bücher weiterkommt, wenn einem, wie freundlicherweise geschehen, geholfen wird. Z.B. habe ich mir meine PHP-Kenntnisse auch weitgehend ohne Buchsammlung angeeignet, denn im Netz wird man mit Tutorials und dergleichen dazu zugeschüttet - Was C++ angeht, gestaltet sich die Situation schwieriger, weil es grundsätzlich schwerer erlernbar ist aber insbesondere im englischsprachigen Raum findet sich da eine Menge brauchbares Material und nicht zuletzt eben auch in Foren. Heute habe ich z.B. wieder eine Menge gelernt, finde ich und außerdem offenbar zur allgemeinen Belustigung beigetragen.
Spaß beiseite: Sind Foren nicht auch dazu da, Wissen nachzufragen, zu verbreiten und zu vermitteln? Andererseits passt die Nutzlast von dem, was Ihr mich nun schließlich freundlicherweise habt wissen lassen, ohne das gönnerhafte Beiwerk locker in zwei überschaubare Sätze rein - und mit Undank hat das nichts zu tun.
Ich finde gut und bin auch dankbar dafür, Hilfe zu bekommen, helfe anderen auch gerne (zweimal geschehen heute - am ersten Tag) und lasse mich nicht entmutigen - von niemand - wirklich nicht, no go.
In Bezug auf meine eingangs erwähnte Fragestellung könnt ihr mir offenbar auch nicht weiterhelfen - schade eigentlich.
Jedenfalls haben auch Zwerge mal klein angefangen und wenn jeder sofort perfekt wäre, bräuchte es wahrscheinlich keine Entwicklerforen, außer vielleicht, um sich unter Experten gegenseitig auf die Schulter zu klopfen - in diesem Sinne nochmals vielen Dank.
-
Du kannst wirklich vieles im Netz erlernen. Mir käme es einfach nie in den Sinn, für eine C++-API/Lib ein Buch zu kaufen (das machen nur Leute die zu viel Geld haben). Bei C++ ist es gerade andersherum.
-
Hacker schrieb:
es gibt bereits professionelle Indikatoren für schlechte Bücher:
Im Titel ist enthalten:
- A bis Z
- 21 Tage (Generell Titel mit Zahlen)
- C/C++
- Schnell
- Gut
- Galileo ComputingDer größte Indikator bleibt weiterhin wenn JW (ich will den Namen nichmal ausschreiben) als Autor draufsteht.
"Grundkurs C++" - keines der Oben angegeben Merkmale zieht (Galileo steht zumindest nicht im Title
).@c+dummie: ich will dich weder entmutigen noch dir empfehlen dir die teuersten Bücher kaufen. Fakt ist aber das die Tutorials im Netz zu C++ meistens mäßig bis schlecht sind - keine Ahnung wies bei PHP ist.
Du kannst ja vorerst bei den Tutorials bleiben, aber auf längere Sicht würde ich trotzdem einen Buchkauf in Erwägung ziehen (im Zweifelsfall zum Geburtstag auf Verwandte abwimmlen
)
-
Das einzig gute war das von volkard, aber das ist mittlerweile auch entweder runter oder auch veraltet...
-
@Hacker - Da Letzte, was ich vorhabe, ist in C-Style zu verfallen oder so weiter. Ich will von vorneherein mit allen Schikanen obejektorieniert programmieren - alles andere kann man heutzutage von vorneherein vergessen - keine Chance.
Ich habe das Teil nochmals umgeschrieben und auf Anraten sämtliche Zeiger rausgeschmissen - auf die Gefahr hin, mich noch mal lächerlich zu machen:
#include <stdio.h> #include <iostream> #include <cstdlib> #include <string> #include <map> #include <vector> using namespace std; class menueItemBase { public: map <string, string> titles; menueItemBase(); ~menueItemBase(){} void show_title(string lang) { cout << this->titles[lang].c_str() << endl; } void set_title(string lang, string title) { this->titles.insert(pair<string, string> (lang, title)); } }; menueItemBase::menueItemBase(){} class menueItem: public menueItemBase { public: vector<menueItemBase>subitems; menueItem(); ~menueItem(){} void show_subitems(string lang) { for (unsigned i = 0; i < this->subitems.size(); i++) { this->subitems[i].show_title(lang); //this->subitems[i].show_subitems(lang); } } }; menueItem::menueItem() {} int main() { menueItem o1; o1.set_title("en", "Main Menue"); o1.set_title("de", "Hauptmenü"); menueItem o2; o2.set_title("en", "Edit"); o2.set_title("de", "Bearbeiten"); menueItem o3; o3.set_title("en", "Preferences"); o3.set_title("de", "Einstellungen"); o2.subitems.push_back(o3); o1.subitems.push_back(o2); o1.show_subitems("de") }Wenn ich die auskommentierte Zeile einkommentiere...
this->subitems[i].show_subitems(lang);...fliegt es mir nach wie vor um die Ohren:
menue_item3.cpp: In member function ‘void menueItem::show_subitems(std::string)’: menue_item3.cpp:40: error: ‘class menueItemBase’ has no member named ‘show_subitems’Hat wirklich niemand 'ne Idee bezogen auf dieses Rekursionsproblem?
Wie kriege ich das hin (außer mit 'gutem Buch kaufen')?
-
Der Compiler hat immer Recht. Die Fehlermeldung ist eindeutig und sehr leicht zu interpretieren. Wo ist das Problem?
-
Das Problem besteht darin, dass entweder ich persönlich es offenbar nicht lösen kann, das Problem auf die von mir angedachte Art und Weise nicht zu lösen ist oder aber (und das wäre wirklich knackig): wenn es auf eine Art und Weise zu lösen ist, die ich nicht kenne und mir einfach jemand zeigt, wie.
Ich halte das noch nicht für gänzlich hoffnungslos. Zwei Foren habe ich heute parallel beackert, morgen vormittag kann ich nicht und morgen nachmittag werde ich weiter rummachen - dann auch international, obwohl es einen Tick schwieriger ist, mein Anliegen auch noch z.B. in korrektes Englisch zu übersetzen - geht aber - Aufwand ca 25% höher.
Gute Nacht - mache jetzt 'nen Abgang

-
Jetzt bin ich doch noch mal kurz aus dem Halbschlaf erwacht
Mir war fast, als würde mal eben jemand dazu anschicken, mir nichtswürdigem Etwas einen grandiosen Codeschnipsel zuzuschieben, der mich endgültig von allen Portierungsproblemen erlöst. Super - morgen ist auch noch ein Tag!
-
Der compiler sagt dir ‘class menueItemBase’ has no member named ‘show_subitems’.
Jetzt such mal in deinem menuItemBaseclass menueItemBase { public: map <string, string> titles; menueItemBase(); ~menueItemBase(){} void show_title(string lang) { cout << this->titles[lang].c_str() << endl; } void set_title(string lang, string title) { this->titles.insert(pair<string, string> (lang, title)); } };nach show_subitems und sag mir, wo das ist.
Kleiner Hinweis: Ich finde es nicht.Jetzt kannst du dir noch überlegen, warum der compiler in menuItemBase diese Funktion sucht. Schau dir dazu mal den vector subitems an.
-
class menueItemBase { public: map <string, string> titles; menueItemBase(); ~menueItemBase(){} void show_title(string lang) { cout << this->titles[lang].c_str() << endl; } void set_title(string lang, string title) { this->titles.insert(pair<string, string> (lang, title)); } virtual void show_subitems(string lang) {} //als überschreibbar definieren //alternativ: virtual void show_subitems(string lang) = 0; };Und dann in menueItem:
class menueItem : public menueItemBase { virtual void show_subitems(string lang) //überschreiben { //mach irgendwas } };virtual wird in C++ für die Überschreibung benutzt, aus PHP müsstest du ja wissen was das ist.
Die Variante in menueItemBase, die ich nicht auskommentiert hab ist wie du siehst einfach leer und wird dann in menueItem überschrieben.
Die auskommentierte Variante ist eine pure-virtual Funktion. Dann kannst du aber von der Klasse keine Instanzen mehr erzeugen.Allerdings können im Vector wieder nur Pointer auf eine Instanz von menueItemBase abgelegt werden, denn sonst wird nicht die überschriebene Variante aufgerufen, wodurch wir wieder bei dem Problem vom Anfang wären, dass du den Speicher selbst freigeben musst.
Schau dir bitte mal shared_ptr und unique_ptr an. Denn die geben ihren Speicher automatisch frei, wenn der vector der sie beinhaltet zerstört wird.BTW: Warum brauchst du überhaupt eine Basisklasse mit virtuellen Methoden, wenn du eh nur eine Klasse ableitest?
-
Dazu muss ich noch etwas hinzufügen.
vector<menueItemBase>subitems;Wenn du (c+dummie) den vector so deklarierst, geht das was Jonas gesagt hat so nicht. Du musst dann Zeiger im vector speichern. Entweder kümmerst du dich dann manuell um die Speicherverwaltung (im Destruktor Speicher freigeben, copy-Konstruktor und Zuweisungsoperator richtig schreiben) oder du verwendest eben shared_ptr oder unique_ptr.
-
@KMT Du schriebst "Jetzt such mal in Deinem menueItemBase... nach show_subitems und sag mir, wo das ist.
Kleiner Hinweis: Ich finde es nicht."Ich habe nur Objekte der Klasse menueBase, und nie der Klasse menueItemBase instantiiert und insofern hat mich irritiert, dass sich der Compiler beschwert, dass die Funktion show_sub_items in meinen Objekten (also Objekten der Klasse der menueItem) nicht verfügbar sein soll.
JonasOSDenver liefert dankenswerterweise weiter unten die offenbar richtige Erklärung.
@JonasOSDenver
Du schreibst: "virtual wird in C++ für die Überschreibung benutzt, aus PHP müsstest du ja wissen was das ist."
Darin scheint das erste Problem zu liegen, weil das Konzept der virtuellen Funktion in PHP (meines Wissens und zumindest in dieser Form) überhaupt nicht existiert. Vielmehr sind in PHP alle Funktionen automatisch virtuell, die nicht privat sind - also public und protected SIND unter PHP virtuell und insofern wäre bei einer ähnlichen Konstruktion in PHP das Problem wohl gar nicht aufgetreten. Überhaupt bestehen in Bezug auf OOP offenbar eine ganze Reihe von gravierenden Unterschieden.
"BTW: Warum brauchst du überhaupt eine Basisklasse mit virtuellen Methoden, wenn du eh nur eine Klasse ableitest?"
Wenn man (ich gehe eigentlich davon aus, dass Du das weißt), Vektoren initialisiert, muss man doch unter C++ (wie bei allen anderen Variablentypen auch) den Datentyp bereits bei der Initialisierung angeben (was in PHP übrigens auch nicht erforderlich ist - PHP ist eine sog. schwach typisierte Sprache).
Leider kennt C++ außerdem den Datentyp 'object' nicht (PHP schon), wohl aber kennt C++ den benutzerdefinierten Datentyp, der auf bereits definierten Klassen beruht.
Daher ist mein Vektor subitems vom Typ menueItemBase und daher benötige ich auch diese Basisklasse - also zunächst nur, um diesen Vektor initialisieren zu können.
Darüber hinaus möchte ich auch alle Funktionen, die ein Objekt menueItem so braucht, als Klassenmethoden deklarieren und nicht außerhalb davon, weil ich diese Klasse später nach Belieben in allem Möglichen inkludieren will, ohne mich dort noch z.B. explizit dauernd mit dem Auslesen von Vektoren beschäftigen zu müssen.
Aus diesem Grund will ich Methoden IN menueItem Base, die Objekte zum Vektor hinzuzufügen bzw. auszulesen und nicht außerhalb. Aus diesem Grund stören mich zur Zeit auch noch die push_back Anweisungen in main().
Natürlich kann ich alle Methoden AUßER show_subitems dann auch gleich in menueItemBase deklarieren, weil ich sie (die Klasse) wegen des benutzerdefinierten Vektors ohnehin benötige. Da menueItem menueItemBase beerbt, geht das auch ohne Weiteres.
show_sub_items kann ich nicht in menueItemBase deklarieren, weil eine Klasse sich nicht selbst referenzieren kann, um den Datentyp für einen Vektor bereitzustellen.
Deine Informationen zu virtuellen Methoden sind sehr interessant und helfen mir wahrscheinlich entscheidend weiter - dafür vielen Dank. Wie gesagt - unter PHP benötigt man die nicht für eine Umsetzung dieser Art - so langsam fällt der Groschen.
Ebenfalls hochinteressant sind Deine Tips bezogen auf shared_ptr und unique_ptr, denn wenn es tatsächlich so ist, wie Du schreibst, bräuchte es im Destruktor von menueItems evtl. nur EINE entsprechende geeignete Anweisung und der Speicher wäre wieder frei. Das werde ich mir unbedingt gleich mal ansehen.
Mit der fertigen Ausarbeitung kann es ein wenig dauern, weil ich heute noch dringend andere Sachen zu erledigen habe.
Vielen Dank noch mal - Du hast mir bisher sehr weiter geholfen - ich hoffe, ich kann mich erkenntlich zeigen.

-
Danke für den Hinweis auf darauf, dass ich dann doch evtl. wieder verstärkt mit Zeigern arbeiten muss. In dem von mir ursprünglich geposteten Listing hat es übrigens von Zeigern nur so gewimmelt aber mir wurde auch gesagt, dass diese das Unterfangen, den Speicherlecks auszuschließen nicht unbedingt vereinfachen.
Ich sehe da ein durchwachsenes Wochenende auf mich zukommen....
-
Wenn der Typ deines Vektors keine Methode "show_subitems" enthält kannst du sie auhc nicht aufrufen. Du instanzierst zwar MenuItem, aber trotzdem kannst du nur auf die in MeuItemBase deklarierten Methoden zugreifen wenn dein Vektor MenuItemBase als Typ hat.
Aber C++ hat einen kleinen Trick: Du kannst innerhalb deiner Klasse einen Pointer auf deine Klasse als Typ für den Vektor benutzen, dazu gleich mehr.Zum Thema shared_ptr/unique_ptr: du brauchst in dem Fall nicht mal einen Aufruf im Destruktor. Google mal nach RAII. Das ist eben das schöne an shared_ptr/unique_ptr: Wenn der vector zerstört wird, dann werden diese auch automatisch zerstört. Denn sie sind eben nicht nur rohzeiger, sondern definieren einen Destruktor der den Speicher auf den sie zeigen deleted.
Im Prinzip kannst du mit diesem Wissen dein Programm folgendermaßen implementieren:
class MenueItem { public: std::vector<std::unique_ptr<MenueItem>> subitems; std::string title; MenueItem(std::string menutitle) : title(menutitle) {}; void show_menu() { std::cout << title << '\n'; for(auto it = subitems.begin(); it < subitems.end(); ++it) { it->get()->show_menu(); } } ~MenueItem() { std::cout << "\nMenue \"" << title << "\" wurde freigegeben"; } }; int main() { MenueItem main("main"); main.subitems.push_back(std::unique_ptr<MenueItem>(new MenueItem("Datei"))); main.subitems.push_back(std::unique_ptr<MenueItem>(new MenueItem("Bearbeiten"))); main.subitems[0]->subitems.push_back(std::unique_ptr<MenueItem>(new MenueItem("Oeffnen"))); main.show_menu(); return 0; }P:\Meine Projekte\VB\TMP\Debug>test main Datei Oeffnen Bearbeiten Menue "main" wurde freigegeben Menue "Datei" wurde freigegeben Menue "Oeffnen" wurde freigegeben Menue "Bearbeiten" wurde freigegeben P:\Meine Projekte\VB\TMP\Debug>Deine Mehrsprachigkeit habe ich zur Vereinfachung mal rausgelassen, kannst du natürlich einfahc wieder hinzufügen.
EDIT: Kein einziges Delete, der Destruktor war nur zum aufzeigen das wirklich alle Sachen freigegeben werden definiert. Also doch kein duchwachsenes WE.

-
Du hast Dir da jetzt (für meine Begriffe) eine Menge Arbeit gemacht und mir diese wahrscheinlich erspart. Allein um Deinen Quellcode zu reproduzieren, benötige ich etwas Zeit, die ich im Moment nicht habe - also erstens um das jetzt mal mit g++ zu kompilieren und auszugeben aber vor allem auch, um es geistig zu reproduzieren und mit meiner Idee in Einklang zu bringen. Das durchwachsene Wochenende erscheint also quasi trotzdem unausweichlich - meine Kapazitäten in der Aufarbeitung derartiger Detailfragen sind außerdem wahrscheinlich vergleichsweise gering.Kann ich irgendwie für Dich voten oder sowas in der Art? Dazu muss ich leider auch noch sagen, dass ich prinzipiell nicht (mehr) spiele. Du führst in Deinen Posts immer an, dass es strafbar ist, in dieser Hinsicht abstinent zu sein.
Wenn ich mir andererseits überlege, was da jetzt auf einmal in beachtlichem Umfang so herüber kommt, finde ich, dass Du damit mutmaßlich schon ein fettes Kapitel in einem C++ - Buch der besseren Art füllen könntest, falls noch nicht geschehen.
Für den Rest der Woche habe ich mir fest vorgenommen, mein kleines Projekt in der vorgeschlagenen Art und Weise fortzusetzen - die Idee als solche in's Gespräch zu bringen: (Multidimensionalität innerhalb von Objekten - und damit ziehe ich mich jetzt aus der Affäre) war glaube ich, grundsätzlich nicht völlig verkehrt. Hier fehlt noch das Danke, danke Emoticon, dafür gibt es das infinite smile ∞

-
c+dummie schrieb:
Kann ich irgendwie für Dich voten oder sowas in der Art? Dazu muss ich leider auch noch sagen, dass ich prinzipiell nicht (mehr) spiele. Du führst in Deinen Posts immer an, dass es strafbar ist, in dieser Hinsicht abstinent zu sein.
Punktesysten oä gibts hier nicht, aber das macht nichts. Wenn ich seh, dass ich jemandem Helfen konnte reicht mir das.
Ich verstehe auch dass es für dich etwas schwieriger ist den Code nachzuvollziehen, ich stehe natürlich jederzeit für Rückfragen zur Verfügung.
Bezüglich meiner Signatur (die wird automatisch angehängt, ich schreib das nicht extra): War "Werbung" für ne Runde Mord in Palermo, aber der Thread ist längst verwaist. Also mach ich mal eine Außnahme bzgl. der Strafe für die Befehlsverweigerung :p Werd die Signatur auch demnächst mal ändern
P.S. zum Thema C++-Buch: Ich habe nicht vor eins zu schreiben, aber selbst wenn: Welcher Verlag verlegt Fachbücher von Minderjährigen?
-
zur Kompilierung ptr ist u.a. unter Debian offenbar Bestandteil von boost. Habe das Komplettpaket also installiert und Deine Source kompiliert - danach:
jonas1.cpp:4: error: ISO C++ forbids declaration of ‘vector’ with no type jonas1.cpp:4: error: invalid use of ‘::’ jonas1.cpp:4: error: expected ‘;’ before ‘<’ token jonas1.cpp:5: error: ‘string’ in namespace ‘std’ does not name a type jonas1.cpp:7: error: expected ‘)’ before ‘menutitle’ jonas1.cpp: In member function ‘void MenueItem::show_menu()’: jonas1.cpp:11: error: ‘cout’ is not a member of ‘std’ jonas1.cpp:11: error: ‘title’ was not declared in this scope jonas1.cpp:13: error: ‘subitems’ was not declared in this scope jonas1.cpp:13: error: unable to deduce ‘auto’ from ‘<expression error>’ jonas1.cpp: In destructor ‘MenueItem::~MenueItem()’: jonas1.cpp:21: error: ‘cout’ is not a member of ‘std’ jonas1.cpp:21: error: ‘title’ was not declared in this scope jonas1.cpp: In function ‘int main()’: jonas1.cpp:28: error: no matching function for call to ‘MenueItem::MenueItem(const char [5])’ jonas1.cpp:2: note: candidates are: MenueItem::MenueItem() jonas1.cpp:2: note: MenueItem::MenueItem(const MenueItem&) jonas1.cpp:29: error: ‘class MenueItem’ has no member named ‘subitems’ jonas1.cpp:29: error: ‘unique_ptr’ is not a member of ‘std’ jonas1.cpp:29: error: expected primary-expression before ‘>’ token jonas1.cpp:29: error: no matching function for call to ‘MenueItem::MenueItem(const char [6])’ jonas1.cpp:2: note: candidates are: MenueItem::MenueItem() jonas1.cpp:2: note: MenueItem::MenueItem(const MenueItem&) jonas1.cpp:30: error: ‘class MenueItem’ has no member named ‘subitems’ jonas1.cpp:30: error: ‘unique_ptr’ is not a member of ‘std’ jonas1.cpp:30: error: expected primary-expression before ‘>’ token jonas1.cpp:30: error: no matching function for call to ‘MenueItem::MenueItem(const char [11])’ jonas1.cpp:2: note: candidates are: MenueItem::MenueItem() jonas1.cpp:2: note: MenueItem::MenueItem(const MenueItem&) jonas1.cpp:31: error: ‘class MenueItem’ has no member named ‘subitems’ jonas1.cpp:31: error: ‘unique_ptr’ is not a member of ‘std’ jonas1.cpp:31: error: expected primary-expression before ‘>’ token jonas1.cpp:31: error: no matching function for call to ‘MenueItem::MenueItem(const char [8])’ jonas1.cpp:2: note: candidates are: MenueItem::MenueItem() jonas1.cpp:2: note: MenueItem::MenueItem(const MenueItem&)Ich gehe davon aus, dass es sich um marginale Probleme handelt - vielleicht irgendwo ne spitze Klammer oder so zu viel.
-
Um C++ programmieren zu lernen ist das Verständnis der Fehlermeldungen (oder das googlen danach) eine wichtige Eigenschaft. Probiere das das nächste Mal selbst zu lösen.
Damit du die Klassen vector<> oder unique_ptr<> zur Verfügung hast, musst du sie importieren. Das geht unter C++ mit #include. Für den Code von Jonas OSDever benötigst du:
#include <iostream> #include <vector> #include <memory>Dann kompillieren:
$ g++ -Wall -Wextra -pedantic -std=c++0x jonas1.cpp -o jonas1 $ ./jonas1Bei dir könnte es Probleme mit unique_ptr geben, da du in Squeeze einen alten GCC hast. Ersetze ihn dann durch
std::tr1::shared_ptr. Bis du mehr verstehst, solltest du alle Pointer als shared_ptr halten.
-
Schwerer Ausnahmefehler: habe überhaupt nichts im header spezifiziert - ich melde mich erst wieder, wenn es rund läuft.
Minderjährige hin oder her - wenn Du über dieses ausgezeichnete Fachwissen verfügst, finde ich es schade, dass Du es (aus welchen Gründen auch immer) nicht veröffentlichen kannst oder willst.
-
c+dummie schrieb:
Minderjährige hin oder her - wenn Du über dieses ausgezeichnete Fachwissen verfügst, finde ich es schade, dass Du es (aus welchen Gründen auch immer) nicht veröffentlichen kannst oder willst.
Da gibt es deutlich erfahrerene Gurus hier im Forum (SeppJ, volkard, seldon vor allem, usw.). Das mit dem Buchschreiben wurde schon öfters angesprochen. Es kostet sehr viel Zeit, evt. (Opportunitäts-)Kosten und Aufwand, so ein Buch zu schreiben und zu veröffentlichen. Und dazu kann nicht jeder gut erklären.
Was die Smart-Pointer angeht: Wenn die Reihenfolge der Speicherfreigabe nicht umbedingt zählt, kann man auch meine neueste Erfindung ausprobieren: Der Müllwagen! Eine Art Allokator der den Speicher automatisch am Ende des Programms freigibt (aber lausig programmiert ist)!
