Multidimensionale Menüstruktur mit OOP und stl::vector
-
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)!

-
Halo,
c+dummie schrieb:
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.
nein, das trifft es nicht ganz.
Der Fehler tritt in PHP nicht auf, weil erst zur Laufzeit bestimmt wird, welche Funktionen aufgerufen werden.
In C++ sieht der Compiler anhand der Klasse deines Objektes genau, welche Methoden du darauf aufrufen kannst. Du hast eine Klasse "menueItemBase" definiert, welche die show_subItem Methode nicht besitzt. Ergo kannst du auf Elemente eines Vektors, welche Elemente vom Typ "menuItemBase" enthält, nicht diese Methode aufrufen.Selbst wenn du in diesem Vektor immer nur "menuItem"-Dinge reintust, welche diese Methode haben, erlaubt dir das der Compiler nicht.
Bei PHP funktioniert genau das. Selbst wenn du per Type-Hinting den Typ der Basis-Klasse angibst, wird es funktionieren. Das hat wohl was mit der Möglichkeit zu tun, Methoden nachträglich hinzuzufügen und/oder der __call-Methode (aber das ist nur eine Vermutung), so dass die potentiellen Fehler (Methode wird auf einem Objekt aufgerufen, welche diese nicht hat) erst zur Laufzeit (und nicht zur Compilezeit) abgefangen werden kann.
Beispiel, was in PHP funktionieren sollte (direkt hier reingetippt, kann also kaputt sein):
class Base { } class Sub extends Base { public function showSub() { echo "Hello World\n"; } } function showHelloWorld(Base $bla) { $bla->showSub(); } $bla = new Sub(); showHelloWorld($bla);In C++ würde (vereinfacht ausgedrückt) der Compiler sich die Funktion showHelloWorld ansehen und bemerken
- die Funktion nimmt ein Base-Objekt entgegen
- ein Base-Objekt hat (aufgrund seines festen Kontraktes, d.h. die Klassendefinition, die in C++ abschließen ist) keine showSub-Methode
-> ergo: es ist zur Compilezeit nicht sicher, ob deine Metode richtig funktionieren kann.Dabei wäre noch zu erwähnen, dass der Compiler während des compilens von showHelloWorld u.U. gar nicht die verschiedenen Aufrufe kennt. Diese können in anderen Compileeinheiten stecken, so dass selbst eine Heuristik zwecklos ist. Und Fehler, die erst zur Laufzeit auftreten, will man ja wirklich nicht haben.
Ich hoffe, ich konnte dir mit meinen (einfachen) Worten ein wenig helfen.
Viele Grüße,
MJM
-
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.
Das du nur menuBase und nie menuItemBase instantiert hast stimmt so nicht.
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); //subitems ist vom typ vector<menuItemBase>. menuItem wird nach menuItemBase konvertiert! (Stichwort slicing) o1.subitems.push_back(o2); //hier das selbe! o1.show_subitems("de")Der compiler hat sich falls du dir die Fehlermeldung anschaust NICHT beschwert das showsubitems nicht in menuItem vorhanden ist. Er hat sich ganz klar beschwert, dass es in menuItemBase nicht vorhanden ist.
Bleibt für dich wahrscheinlich noch die Frage, was slicing ist.Das entsteht durch folgendes: Ein menuItemBase objekt enthält eine map<string, string>. Die braucht Speicherplatz. Ein menuItem enthält ein menuItemBase, und einen vector<menuItemBase>. Braucht also MEHR Speicherplatz als ein menuItemBase. Dieser zusätzliche Speicherplatzbedarf passt aber in einen vector<menuItemBase> nicht rein. Deswegen wird der menuItem teil einfach abgeschnitten. Zeiger haben dieses Problem nicht.
-
Hacker schrieb:
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)!

Ist das deine Technik um den Programmablauf zu verlangsamen?

Am Ende vom Programm selbst au8fzuräumen ist Unsinn, wenn das Betriebssystem alle Resourcen auf einen Schlag nehmenkann und deswegen deutlich schneller ist.
-
Erst mal vielen Dank für die neuen, interessanten Beiträge hier!!!
@Jonas OSDever
Alles im Lot - Dein hochinteressantes Listing läuft absolut rund, womit ich vermutlich alles beisammen habe, was ich für die weitere Umsetzung meiner Menüstruktur benötige. Es kann natürlich auch im Weiteren immer mal wieder zu Problemen kommen, weil ich halt von beinahe Allem wenig Ahnung habe. Andererseits habe ich erheblich dazugelernt.
Ich hoffe, Dich richtig so verstanden zu haben, dass sich jedwedes delete() in Deinem Programm erübrigt.
@debianer
Mein Inkludierungsproblemchen (#include <memory>) hatte ich schon selbst in den Griff bekommen, bevor ich hier nochmals reingeschaut hatte, trotzdem danke - schön außerdem, hier auch Experten für mein Lieblings-OS anzutreffen.
Soweit ich weiß, ist die neuste GGC-Version 4.6 - meine ist(Debian 4.4.5-8) 4.4.5
Auch mit einem knappen g++ -o jonas1 -std=c++0x jonas1.cpp habe ich das Listing schließlich ohne Probleme kompilieren können. Daher ist mir nicht unbedingt klar, wozu die anderen Schalter dienen (-Wall -Wextra -pedantic). Werde mich gleich mal schlau machen.
@MJM
Dein PHP-Listing ist so, wie es da steht lauffähig, obwohl es mir zuerst den Angstschweiß auf die Stirn getrieben hat - so was kommt mir zum ersten Mal unter
Es mag daran liegen soll, das ich unter PHP noch nie das Bedürfnis hatte eine Klasse als Funktionsargument zu übergeben. Dein Programm läuft auch, wenn man das nicht tut, also function showHelloWorld($bla) geht auch.
Zwar ist das off-topic aber zum Thema PHP möchte ich noch ganz nebenbei erwähnen, wie lächerlich einfach die ganze Aufgabe damit zu lösen ist (Kinderkram) - keine Klassen für benutzerrdefinierte Vektoren und virtuelle Funktionen ect... - z.B.:
<?php class menueItem { private $value, $items; public function __construct($value) { $this->value = $value; } public function append_object($obj) { $this->items[] = $obj; } public function show_object_values() { echo "\n<pre>".$this->value."</pre>"; if(isset($this->items)) { foreach ($this->items as $item) { $item->show_object_values(); } } } public function __destruct(){} } $obj1 = new menueItem("Menüstruktur"); $obj2 = new menueItem('Bearbeiten'); $obj3 = new menueItem('Einstellungen'); $obj4 = new menueItem('Plugins'); $obj3->append_object($obj4); $obj2->append_object($obj3); $obj1->append_object($obj2); $obj1->show_object_values($obj1); ?>Ausgabe:
Menüstruktur
Bearbeiten
Einstellungen
Plugins
-
Der Code 1:1 nach C++ übernommen:
#include<iostream> #include<string> #include<vector> class menueItem { private: std::string value; std::vector<menueItem> items; public: menueItem(std::string const& value) : value(value) {} void append_object(menueItem const& obj) { items.push_back(obj); } friend std::ostream& operator<<(std::ostream& out, menueItem const& item) { out<<item.value<<"\n"; std::vector<menueItem>::const_iterator i=item.items.begin(), end=item.items.end(); while(i!=end) { out<<*i; ++i; } return out; } }; int main() { menueItem obj1("Menüstruktur"); menueItem obj2("Bearbeiten"); menueItem obj3("Einstellungen"); menueItem obj4("Plugins"); obj3.append_object(obj4); obj2.append_object(obj3); obj1.append_object(obj2); std::cout<<obj1<<"\n"; }sehe da keinen einzigen relevanten Unterschied.
Ich war so frei und habe den operator<< statt show_values() genommen - aber im Prinzip ists das gleiche.PS:
Der Code ist so halt Schrott - ist er in PHP aber auch. Weil man nix damit machen kann.
-
"Der Code ist so halt Schrott - ist er in PHP aber auch. Weil man nix damit machen kann."
Um auf dieses pauschale und vernichtende Urteil eines offenbar äußerst verdienten Teilnehmers Bezug zu nehmen:
Insbesondere Deine Schlussbehauptung kann ich so nicht stehen lassen, weil die Tatsache, das etwas, mit dem man nichts machen kann, weil es lediglich ein Beispiel für einen Bestandteil von etwas anderem ist, noch lange nicht bedeutet, dass das Gesamtgebilde Schrott ist. Außerdem war die Ausgangslage lediglich die, dass ich mich bemüht habe, ein Problem trotz ziemlich grundlegender Anfängerprobleme so darzustellen, dass es zu verstehen und einfach zu bearbeiten ist.
echo; ist auch Schrott, weil man nix damit machen kann und weil es nichts macht.
echo "Hello World"; ist nach meinem Verständnis dagegen kein Schrott, weil dabei unten was mehr oder weniger Sinnvolles herauskommt.Ich kann zumindest mit meiner PHP-Variante genau das, was ich tue: Multidimensionale Objekte erzeugen und sie wieder auslesen. Im Übrigen kann ich das nun auch mit C++ - zumindest wenn ich hier durch bin.
Zum praktischen Nutzen: nach entsprechender Anpassung kann ich zum Beispiel unter PHP einen häufig verwendeten Nested Set aus einer Datenbank auslesen oder eine XML-Datei aus dem Dateisystem, selbiges auf diese Weise darstellen, im Arbeitsspeicher cachen (memcached) und erreiche hierdurch selbst unter PHP vergleichsweise niedrige Latenzen (ohne dauernde Zugriffe auf Datenbanken oder das Dateisystem).
In vielen Fällen wäre es auch praktischer, derartige Aufgaben mit Hilfe multidimensionaler und teilweise assoziativer Arrays umzusetzen, muss es aber nicht (z.B. dann nicht, wenn die Datenbasis ihrerseits aus serialisierten Objekten besteht).
Wie dem auch sei - danke insbesondere für Dein Listing. Ich werde es mir ebenfalls eingehend zu Gemüt führen - schönen Abend noch.
-
c+dummie schrieb:
Insbesondere Deine Schlussbehauptung kann ich so nicht stehen lassen, weil die Tatsache, das etwas, mit dem man nichts machen kann, weil es lediglich ein Beispiel für einen Bestandteil von etwas anderem ist, noch lange nicht bedeutet, dass das Gesamtgebilde Schrott ist. Außerdem war die Ausgangslage lediglich die, dass ich mich bemüht habe, ein Problem trotz ziemlich grundlegender Anfängerprobleme so darzustellen, dass es zu verstehen und einfach zu bearbeiten ist.
Die richtige Art eine Menustruktur zu machen wurde hier schon genannt. Es laeuft ueber Polymorphie. Schliesslich willst du ja nicht nur einen Text ausgeben sondern ein Menupunkt hat bestimmtes verhalten. uU hat er einen Helptext und aufjedenfall hat er eine Aktion.
Wenn wir zB folgenden Code haetten:
#include<iostream> #include<string> #include<vector> class MenuItem { private: std::string name; std::vector<MenuItem*> items; //besser waere boost::ptr_vector public: MenuItem(std::string const& name) : name(name) {} virtual ~MenuItem() { std::vector<MenuItem*>::const_iterator i=items.begin(), end=items.end(); while(i!=end) { delete *i; ++i; } } std::string const& getName() const { return name; } void append(MenuItem* obj) { items.push_back(obj); } virtual void action() = 0; virtual void displayChildren(std::ostream& out) const { std::vector<MenuItem*>::const_iterator i=items.begin(), end=items.end(); while(i!=end) { (*i)->display(out); ++i; } } virtual void display(std::ostream& out) const { out<<name<<"\n"; } }; std::ostream& operator<<(std::ostream& out, MenuItem const& item) { item.display(out); item.displayChildren(out); return out; } class SeparatorMenuItem : public MenuItem { public: SeparatorMenuItem(std::string const& name) : MenuItem(name) {} void action() { //donothing } void display(std::ostream& out) const { out<<" --- "<<getName()<<" --- \n"; } }; class CallFuncMenuItem : public MenuItem { public: typedef void (*CallFuncType)(); private: CallFuncType callFunc; public: CallFuncMenuItem(std::string const& name, CallFuncType callFunc) : MenuItem(name), callFunc(callFunc) {} void action() { callFunc(); } }; class PrintTextMenuItem : public MenuItem { private: std::string text; public: PrintTextMenuItem(std::string const& name, std::string const& text) : MenuItem(name), text(text) {} void action() { std::cout<<text<<"\n"; } }; void bearbeiten() { std::cout<<"do some stuff\n"; } int main() { SeparatorMenuItem base("Menue"); base.append(new CallFuncMenuItem("Bearbeiten", bearbeiten)); base.append(new PrintTextMenuItem("Plugins", "not yet implemented")); std::cout<<base<<"\n"; }Dann haben wir ploetzlich polymorphes verhalten im Menu. Wir koennen komplexere Strukturen darstellen weil wir automatisch untermenues haben. Wir haben unterschiedliche Aktionen die pro Menu Item aufgerufen werden koennen, etc.
So in etwa sollte der Code aussehen.
PS:
Wenn du natuerlich alles statisch haben willst: wozu so eine Struktur? Dann tut es ein PHP array bzw. std::vector auch. Aber die wirkliche Macht von so einer Struktur bekommst du nur durch Polymorphie.Schau dir zB mal an wie man so ein Menu in JavaScript machen wuerde. Da hat man pro Item ja eine Aktion. Dort wuerde man zu jedem Item unterschiedliche Callbacks hinterlegen. Und bedenke: verschachtelte Items sollten auch moeglich sein...
-
Bisher bin ich nicht davon ausgegangen, dass es Sinn macht, so einem unwürdigen Menüpunkt auch noch ein eigenes Verhalten zuzubilligen
Mit dieser Perspektive habe ich mich bisher noch nicht mal theoretisch auseinandergesetzt. Für mich war so ein Menü zunächst mal eine hierarchich strukturierte Angelegenheit, die es zu behandeln gilt, wenngleich es durchaus Sinn macht, dass selbst so ein an sich beschränkter Menüpunkt selbst sich Zeit seines Lebens und von vorne herein bereits darüber im Klaren sein sollte, was ihm das Schicksal in die Wiege gelegt hat 
Ich muss Dich aber trotzdem für heute insofern unterbrechen, als ich wirklich in Bezug auf solche Feinheiten (oder das grundlegende Verständnis, wenn Du so willst) auf der Skala relativ weit unten anzusiedeln bin - Du da oben im 7. Himmel der objektorientierten C++ Programmierung - ich: ein Wurm, der geradezu herausfordert, zertreten zu werden.
Wie auch immer - ich bin nicht wirklich ein Wurm, aber um aufzuarbeiten, womit Du mich eben konfrontiert hast, benötige ich mit Sicherheit Tage, wenn nicht Wochen meiner kostbaren Lebenszeit - ich muss mich jetzt erst mal entspannen.
Würmer machen sich oft keinen Begriff davon, was sie so alles können sollten, bevor sie die falschen Fragen stellen

Ich betrachte das hier aber nicht als mein Terretorium - nur kann ich nicht mit Dir nicht über Deine Listings diskutieren, außer sie unreflektiert zu bestaunen, weil, ich sie (noch) nicht aufarbeiten kann. Die Lernkurve ist zu steil aber das muss ja nicht so bleiben.
Gute Nacht für heute, danke noch mal!
-
@Shade
Ich hab da ne Frage. In Z. 35 & 18 benutzt du statt einer einfachen for-Schleife dieses while-Ding. Mir ist dein Code-Stil egal, aber hat das irgendeinen Grund den ich nicht kenne, bzw. überseh' ich da was? Ist schon irgendwie ungewöhnlich, genau für sowas gibt's doch die for-Schleife und ich finde das deutlich übersichtlicher als das was Du da benutzt, weil man sofort sieht, wo Zählvariable, Bedingung und Handlung sind..EDIT: Klar meine ich 35..
-
Incocnito schrieb:
@Shade
Ich hab da ne Frage. In Z. 42 & 18 benutzt du statt einer einfachen for-Schleife dieses while-Ding. Mir ist dein Code-Stil egal, aber hat das irgendeinen Grund den ich nicht kenne, bzw. überseh' ich da was? Ist schon irgendwie ungewöhnlich, genau für sowas gibt's doch die for-Schleife und ich finde das deutlich übersichtlicher als das was Du da benutzt, weil man sofort sieht, wo Zählvariable, Bedingung und Handlung sind..Nein, Shades Coding style ist schön. Es ist viel schöner das separat zu schreiben, als alles in eine einzige Zeile zu packen, nur für das bisschen lokalisierung.
Angenommen du meinst Z. 35
