Menü Klasse - Konstruktor Problem
-
Stromberg schrieb:
...
menu(string P1); // } menu(string P1,string P2); // } menu(string P1,string P2,string P3); // } Konstruktor überladen, sodass man menu(string P1,string P2,string P3,string P4); // } die Anzahl der Menüpunkt aussuchen menu(string P1,string P2,string P3,string P4,string P5); // } kann. (Maximaleanzahl=7 Menüpunkte) menu(string P1,string P2,string P3,string P4,string P5,string P6); // } menu(string P1,string P2,string P3,string P4,string P5,string P6,string P7); // }...
Äh ... warum nimmst Du nicht Defaultparameter (falls es nur relativ wenige Parameter sind) oder einen
menu(vector<string> const& allePs); // Geht natürlich nicht, wenn man unterschiedliche Typen hat oder die Initialisierungsliste nutzen mussHalte ich für wesentlich einfacher, übersichtlicher und sicherer ...
Gruß,
Simon2.
-
LordJaxom schrieb:
Um nochmal hier drauf einzugehen: Das klappt? Prima! Ist trotzdem undefiniert...
Und genau das ist das Problem an undefiniertem Verhalten: Es ist nicht gesagt dass es nicht klappt.
also, das will ich jetz aber wirklich verstehen! :p
So, hab hier dieselbe funktion nochmal ein bisschen anders umgeschrieben, ohne dieser ganzen makros (in wirklichkeit sehen die makros auch nicht viel anders aus, nur n bisschen schwerer lesbar, finde ich... ) Wie auch immer, die selbstgebackenen funktionieren auch.Vector2D myAverageEllipseFunction(int iNumArgs, ...){ //entspricht in etwa: va_list pArgList char* pArgList; //entspricht in etwa: va_start(pArgList,iNumArgs) pArgList=(char*)((long)&iNumArgs+sizeof(iNumArgs)); Vector2D v=Vector2D(0.0f, 0.0f); Vector2D arg; for(int i=0; i<iNumArgs; i++){ //argument lesen, entspricht in etwa va_arg(pArgList,Vector2D); arg=*((Vector2D*)(pArgList)); //pointer versetzen, macht auch va_arg pArgList=(char*)((long)pArgList+sizeof(Vector2D)); v=Vector2D(v.x+arg.x, v.y+arg.y); } //was va_end genau amcht, weis ich nicht pArgList=(char*)0; v=Vector2D(v.x/iNumArgs, v.y/iNumArgs); return v; }Sieht zwar ziemlich finster aus, dafür sind hier keine makros, von den unklar ist, was die eigentlich tun.

Für diese ellipse braucht man nur sizeof() und casting in (char*) und zurück.
Frage: was davon funktioniert bei c++ Objekten anders als bei primitiven datentypen wie char oder int? solange alle argumente nacheinander im stack abgelegt werden, ist doch alles in ordnung. Oder?
-
Dann verstehe: Objekte über Ellipsen zu übergeben ist undefiniert. Das sagt der Standard. Der Standard gibt die Sprache vor. Du programmierst in der Sprache.
Was sagt uns das? Es ist vollkommen uninteressant, ob das auf Deiner Plattform / mit Deinem Compiler / .... jetzt gerade funktioniert, denn es ist nicht garantiert, dass es woanders auch funktioniert. Es ist nichtmal garantiert dass es unter denselben Voraussetzungen in der nächsten Mondphase noch funktioniert. Es ist schlicht und ergreifend undefiniert.
Über das Warum mag ich hier garnicht philosophieren, auch weil ich die Gründe selbst nicht vollständig kenne. Aber da es laut Standard undefiniert ist brauche ich garnicht viel drüber nachdenken, warum (und unter welchen Umständen) es dennoch funktionieren könnte :p
Ich habe gesprochen (How!)

-
@Simon2
Jop das hab ich auch schon erkannt des es so ziemlich unübersichtilich ist, deshlab hab ich doch nochmal eine neue "menu Klasse" geschreiben, in der man nun die Menüpunkte über die Funktion add_menu_point("blablab") hinzufügen kann. Und wie schon gesagt ich wollte nicht mit vector arbeiten.
-
Ich bitte die Adminstratoren bzw Moderatoren diesen Thread zu schließen. Mehrere saubere Lösungsvorschläge wurden bereits presentiert, doch scheint der Threadersteller nicht einzusehen, das seine Lösung einem äußerst unsauberen Code-Stil entspricht.
@Threadersteller:
Sorry wenn ich die Mods jetzt bitte den Thread zu schließen ... aber guck dir erstmal dein Buch weiter an bevor du die Klasse schreibst ... es bringt dir nix hier wildes Pointerschubbsen zu betreiben ... wenn du bei vectoren usw. bist kannst du dich nochmal an die Aufgabe wagen und dir dann evt. nochmal meinen oder auch die Lösungsvorschläge anderer anzugucken.
-
bevor das ganze hier geschlossen wird:
@LordJaxom:LordJaxom schrieb:
Es ist vollkommen uninteressant, ob das auf Deiner Plattform / mit Deinem Compiler / .... jetzt gerade funktioniert:D
okay, ich muss zugeben, dass ich das auf einer einzigen plattform, mit einem einzigen compiler getestet habe
kann mir jedoch trotzdem nicht vorstellen, dass es anderswo nicht funktioniert, weil es mir als die einzige logische lösung erscheint, einfach alle argumente nacheinander im speicher abzulegen. Na gut, der compiler wirds schon besser wissen. Dann ists halt undefiniert.@(D)Evil: naja, der threadersteller hat das ganze hier ja nicht vollgemüllt: ich wars
Ausserdem kann man doch nicht von jedem gleich verlangen, dass er von anfang an immer nur mit den perfekten lösungen weiterarbeitet, wenn der Stromberg mit den vectoren klarkommt, wird er bestimmt einsehen, dass du von anfang an recht hattest 
-
@(D)Evil
Also ich weiß nicht was jetzt dein Problem genau ist? Ich will doch bloß nicht mit "vector::std" arbeiten. Also ich persönlich wüsste jetzt keinen Grund warum man den thread hier schließen sollte. Außerdem ist der Thread nun sowieso für mich abgeschlossen gewesen, weil ja eigentlich alle gesagt wurde. Aber ich will da niemand im wege stehen wenn sich (D)Evil freut und erst wieder ruhig schlafen kann wenn der Thread hier geschlossen ist, von mir aus dann schließt ihn, kein Problem.
Und was du genau mit deinem Pointerschubsen meinst, verstehe ich auch nicht. Vll. ist es mit "std::vector" einfacher, aber ich weiß nicht was gegen meine Klasse spricht? (siehe Beitrag vom 00:05:25 18.03.2007 "Seite2").
Okay vll. ist die nicht so professionell, also ich bin zufrieden mit der.
Und was ist z.B. an der Funktion "change_size" falsch? Es ist doch eine gute Übung mal so eine Funktion zu schreiben, um zu schauen wie es geht ein Array nachträglich zu vergrößern.
Und der Rest finde ich ist selbsterklärend und ich finde das gar nicht unnötig kompliziert. Ich denk schon das man die Klasse um einiges, in deinen oder in manchen anderen Augen hier besser schreiben kann, aber ich bin damit zufrieden.
-
Stromberg schrieb:
...Und wie schon gesagt ich wollte nicht mit vector arbeiten.
Sorry, habe ich wohl übersehen.
Warum denn nicht ?
Mit Deinem "add_menu_point()-Ansatz" veränderst Du natürlich grundlegend Verhalten und Design Deiner Klasse: Sie hat nun einen "fließenden Zustand" und nicht einen, der zur "Geburt" festgelegt wird.
Vorteil: Du kannst konsistenter zur Laufzeit ändern.
Nachteil: Du musst sehr aufpassen, dass Du immer in einem konsistenten Zustand bist (sprich: "Immer alles ermöglichen und überprüfen").Kann sein (und Dein Projekt klingt auch danach), dass es genau das ist, was Du willst/brauchst.
Wenn es aber anders ist, und Du schon eine "feste Klasse" (mein persönlicher Ausdruck; damit meine ich: Man kann nur ein gültiges Objekt anlegen und spart sich damit Initialisierungs- uind Prüforgien) brauchst, solltest Du dem vector nochmal eine Chance geben.
Das hat nichts mit "ich brauch's eben nicht so professionell" zu tun, sondern einfach damit, dass vector Dir genau die Arbeit UND die Möglichkeiten, Fehler zu machen, abnimmt. Gerade Anfängern würde ich eher zum vector raten als zum "Rad selbst erfinden" (Gerade, weil dieses "Rad" relativ lang den Anschein wahren kann, zu funktioneren, um Dir dann umso herzhafter und unbarmherziger in den Hinter zu beißen). ... und dieses "Rad" haben Andere (Bessere) schon lange besser erfunden ... und "vector" genannt.
Kurz gesagt: Mit vector ist es einfacher, kürzer, sicherer, übersichtlicher und wartbarer => und das alles ohne Nachteil.
Gruß,
Simon2.
-
der nachteil ist, dass man dann an einem düsenjet herumbastelt, ohne zu wissen, wie ein rad funktioniert

Ich finde, zu übungszwecken ist es eigentlich ganz gut, sich n paar mal von solchen selbstgebastelten rädern "in den Hintern beissen zu lassen", statt gleich eine optimale lösung irgendwo rauszukopieren, das härtet ab

-
Andrey schrieb:
der nachteil ist, dass man dann an einem düsenjet herumbastelt, ohne zu wissen, wie ein rad funktioniert

Ich finde, zu übungszwecken ist es eigentlich ganz gut, sich n paar mal von solchen selbstgebastelten rädern "in den Hintern beissen zu lassen", statt gleich eine optimale lösung irgendwo rauszukopieren, das härtet ab

Stimmt ... aber könnte das der ASM-Programmierer dem C++-Programmierer nicht genauso vorwerfen ? Oder der Chipdesigner dem ASM-Entwickler ? Oder der Halbleiterspezialist dem Chipdesigner ? Oder der Siliziumschürfer dem Halbleiterspezialisten ? Oder ... ?
Ich glaube, man lernt gutes Programmieren am ehesten durch das Schreiben guter Programme ... und zu guten Programmen gehört IMO auch die Anwendung der optimalen (=ab besten zielgerichteten) Technik.
Ich hatte bislang nicht den Eindruck, dass das Projekt, um das es hier geht, um die Frage "wie finktioniert eigentlich vector ?" kreist, sondern eigentlich etwas Anderes zum Ziel hat ...
Gruß,
Simon2.
-
So jetzt hab ich noch eine Frage.Jetzt vergesst einfach mal kurz den Programm-Code von meiner Klassse (auch wenn er schlecht ist) und schaut lieber bitte mal aufs "Handling", und zwar folgendes: Ich poste jetzt hier erst mal nochmal kurz die Klasse wie se jetzt gerade ausschaut.
main.cpp
#include <iostream> #include "menu.h" #include "ic.h" using namespace ic; using namespace shorties; using namespace std; int main() { bool end=true; menu Startmenu; Startmenu.add_menu_point("NEU STARTEN"); Startmenu.add_menu_point("WEITER"); Startmenu.add_menu_point("ZURUECK"); Startmenu.add_menu_point("OPTIONEN"); Startmenu.add_menu_point("ENDE"); menu Optionen; Optionen.add_menu_point("BILD"); Optionen.add_menu_point("SOUND"); Optionen.add_menu_point("ZURUECK"); while (end) { Startmenu.Draw(); } return 0; }menu.h
#ifndef STANDARD_H_INCLUDED #define STANDARD_H_INCLUDED #include <string> //#include "ic.h" class Array { public: Array(); virtual ~Array(); void change_size(std::string **TempArray,int laengeALT,int laengeNEU); }; class menu : public Array { public: menu(); ~menu(); void add_menu_point(std::string name); short Draw(int y=0,int interval=0); //P1= Y Achse in der Konsole von dem Menü P2= Interval in der die Menüschritt //dargestellt werden sollen, also 1 Zeile 2 Zeilen.....Abstand short keystroke(); void animation(int counter); void key_controll(); short GetKey() {return key;} short GetChapter() {return chapter;} private: std::string *P; int number_of_P; short key; short chapter; }; #endif // STANDARD_H_INCLUDEDmenu.cpp
#include "menu.h" #include <conio.h> #include <iostream> #include "ic.h" using namespace ic; using namespace shorties; //###class Array ### Array::Array() { } Array::~Array() { } //Funktion um ein Array nachträglich zu vergrößern void Array::change_size(std::string **TempArray,int laengeALT,int laengeNEU) { std::string *temp=new std::string[laengeALT]; for (int i=0;i<laengeALT;i++) { temp[i]=(*TempArray)[i]; } delete [](*TempArray); *TempArray=0; *TempArray=new std::string[laengeALT+laengeNEU]; for (int i=0;i<laengeALT;i++) { (*TempArray)[i]=temp[i]; } delete []temp; } //### class menu ### menu::menu() :P(new std::string[1]),number_of_P(1), key(0),chapter(0) { } menu::~menu() { delete P; } //schreibt die menü namen hin und regelt das menü short menu::Draw(int y,int interval) { con.setCurPos(0,y); for (int i=0;i<number_of_P;i++) { animation(i); std::cout << P[i] << "\n"; for (int j=0;j<interval;j++) { std::cout << "\n"; } } keystroke(); key_controll(); con.clear(FG_BLACK); return key; } //funktion um einen neuen menüpunkt hinzuzufügen void menu::add_menu_point(std::string name) { change_size(&P,number_of_P,1); P[number_of_P-1]=name; number_of_P++; } //speichert die tastseneingabe short menu::keystroke() { key=getch(); return key; } //erstellt die textfarbe anhand der improved console void menu::animation(int counter) { con.setTextColor(FG_WHITE); if (chapter==counter) con.setTextColor(FG_RED); } //kontrolliert das "switchen" mit der "S" und "W" Taste, und regelt es void menu::key_controll() { if (key==115) { chapter=chapter+1; } if (key==119) { chapter=chapter-1; } if (chapter>number_of_P-2) { chapter=number_of_P-2; } if (chapter<0) { chapter=0; } }Und mit "ic.h" und "ic.cpp" is natürlich die coole "improved console" gemeint, aber die brauch ich ja wohl net zu posten.
So wie man in der "main.cpp" erkennen kann, kann man mit "add_menu_point("..");" einen Menüpunkt hinzufügen, und wenn man dann die Methode "Draw()" in eine Schleife schreibt dann schaut das ganze aus, wie ein halbwegs normales Menü, in dem man mit den Tasten "W" und "S" hoch und runter "switchen" kann.
Ja gut, man beachte nun die Funktion, "GetKey()", mit der kann man die Elementvariable "key" aufrufen (also ihren Wert halt). In "key" wird der letzte Tastendruck (ASCII) gespeichert. Ja gut ich hätte das jetzt irgendwie so gemacht das wenn jetzt Enter gedrückt wird (ASCII=13) dann würde ich halt abfragen:while(end) { if (GetKey()!=13) Startmenu.Draw(); if (GetKey()==13) { ...... } }So und dann würde ich schauen was gerade in der Elementvariable "chapter" steht. Da steht nämlich immer drin bei welchem Menüpunkt man gerade ist [beginnnt aber bei 0 und nicht bei 1). (0=1ter Menüpunkt, 1=Zweiter Emnüpunkt....)
Der Menüpunkt Option steht an 4ter Stelle (aber weils bei 0 anfängt wärs in chapter 3), also könnte ich ja dann abfragen:while(end) { if (GetKey()!=13) Startmenu.Draw(); if (GetKey()==13) { if (chapter==3) Option.Draw(); } }So wie einem jetzt aber langsam unschwer aufällt, wird der Code ein richtiges Kuddelmouddel. Man stelle sich vor "Option" hätte noch 3-4 Untermenüs.... dann wäre das ja ein "Horrorcode" mit hundertausenden ineinander verschachtelten "if..." Bedingungen, wo sich keiner mehr auskennt. Also ich zumindestens. Also das ist ja wohl dann SCHWACHSINN!!
Mh aber wie würet ihr den dann die Übergänge gestallten? Gibt da irgend eine Programmiertechnik.... irgend nen clou wie mach ich das jetzt am besten???
Wenn ich da in den Menüpunkten "rumswitchen möchte"???
Irgendwie das es auch weniger Schraibarbeit wird und auch n bisschen algemeiner.
Oder is meine Klasse schon so verkorkst? Is das eine blöde Idee, jedes Menü in ein eigense Objekt zu spalten? Weiß jemand eine Trickreiche einfache Lösung, die den Code so überschaubar wie möglich macht?
So ich hoffe mal es macht sich jemand die Mühe und liest diesen Beitrag hier, und weiß vll. weiter.Dankeschön schon mal im Voraus.
-
Mh also ich hab die "main.cpp" jetzt mal so gemacht:
#include <iostream> #include "menu.h" #include "ic.h" using namespace ic; using namespace shorties; using namespace std; int main() { bool end=true; menu Startmenu; Startmenu.add_menu_point("NEU STARTEN"); Startmenu.add_menu_point("WEITER"); Startmenu.add_menu_point("ZURUECK"); Startmenu.add_menu_point("OPTIONEN"); Startmenu.add_menu_point("ENDE"); menu Neu_Starten; Neu_Starten.add_menu_point("LEICHT"); Neu_Starten.add_menu_point("SCHWER"); menu Weiter; Weiter.add_menu_point("JA ?"); Weiter.add_menu_point("NEIN ?"); menu Zurueck; Zurueck.add_menu_point("JA ?"); Zurueck.add_menu_point("NEIN ?"); menu Optionen; Optionen.add_menu_point("BILD"); Optionen.add_menu_point("SOUND"); Optionen.add_menu_point("ZURUECK"); menu Ende; Ende.add_menu_point("JA ?"); Ende.add_menu_point("NEIN ?"); while (end) { if (Startmenu.GetKey()!=13) Startmenu.Draw(); else { switch(Startmenu.GetChapter()) { case 0: Neu_Starten.Draw(); break; case 1: Weiter.Draw(); break; case 2: Zurueck.Draw(); break; case 3: Optionen.Draw(); break; case 4: Ende.Draw(); break; } } } return 0; }Es funktioniert zwar, aber irgendwie finde ich das hässlich oder? Das ist doch kein guter Programmier-Stil? Und ich mein wenn dann jede Unteroption nochmal 1-2 andere Unteroptionen hat dann blickt man da zum Schluss ja wohl gar nimmer durch schätz ich ma. Hmm oder findet ihr das so okay? Vll. gibts ja nur den Weg hier und es geht nicht einfaher? Vll. gehts nur so umständlich? Wie würdet ihr den das machen?
Dankeschön schon mal im Voraus.