//wie enum-artige struktur mit operator++
-
muffmolch schrieb:
Sponatn würd eich jetzt eine eigene Klasse schreiben, die const ints als Member besitzt un den ++/-- operator überladt. Aber das geht doch sicherlich eleganter, oder?
Nein - Klassen sind elegant.

Aber da ist ja nicht viel dabei, mit einer Klasse bist du sowieso flexibler. Du kannst dann auch gleich sicherstellen, dass der
operator++richtig überläuft, sodass du nur die 4 Werte annehmen kannst. Die String-Umwandlungsmethode kannst du auch gleich implementieren. Eventuell wäre auch ein überladener Cast-Operator nachintetwas; das hängt halt von deinen Anforderungen ab.Wenn du willst, kannst du ja auch klassen-intern ein
enumdefinieren, um die Konstanten nach aussen anzubieten.
-
mit eleganter meinte ich sowas wie irgendeine abgefahrene template klasse.
meine grauen hirnzellen arbeiten jetzt nach 16h arbeit nimme rso recht. hast du grad ne quick and dirty loesung zur hand? eins ohne enum? denn so ganz wie ich dann eine typsichere übergabe mache seh grad nicht... Denn die innerhalb der Klasse gehaltenen Typen sind ja wiederum ints... anders bei einem template, dass eben undefiniert für bestimtme richtugnen sein koennte
-
Hmm, da hast du Recht. Ganz typsicher sind Enums nicht... Aber Templates scheinen mir hier der falsche Ansatz zu sein.
Ich bin übrigens gerade an deiner Lösung, die Klasse könnte grösser werden (von der Funktionalität, nicht vom Speicherplatz). Aber ich versuche, Typsicherheit einigermassen einzuhalten.

-
Also da wäre mal ein Ansatz. Ich hab einfach mal ein paar willkürliche Funktionen dazugefügt. Wahrscheinlich gibt es eine bessere Lösung, aber fürs Erste sollte es reichen.
class Direction { public: enum DirectionType { East, North, West, South }; static DirectionType StartDir(); static DirectionType EndDir(); public: Direction(DirectionType NewDir); DirectionType GetDir(); std::string ToString(); void SetDir(DirectionType NewDir); Direction& operator= (DirectionType NewDir); // Präfix-Operatoren Direction operator++(); Direction operator--(); // Postfix-Operatoren Direction operator++(int); Direction operator--(int); private: int myDir; }; bool operator== (const Direction& Left, const Direction& Right); bool operator!= (const Direction& Left, const Direction& Right); bool operator<= (const Direction& Left, const Direction& Right); bool operator< (const Direction& Left, const Direction& Right); bool operator>= (const Direction& Left, const Direction& Right); bool operator> (const Direction& Left, const Direction& Right); int main() { for (Direction dir = Direction::StartDir(); dir <= Direction::EndDir(); ++dir) { } }Wenn du keine anderen Werte als die im Enum zulassen willst, könntest du ja Exceptions verwenden. Falls du den Typ nur zum Iterieren brauchst, kannst du ja das Enum privat machen und nur die statischen Methoden anbieten.
-
Ich finde "Dummie"s Beispiel gut, Klassen finde ich hier vollkommenen Overkill.
Achso, kleine Änderung von Dummies Code:
enum Dir { EAST, NORTH, SOUTH, WEST, START_DIR = EAST, END_DIR = WEST+1 }; // Keine Ahnung, ob diese Funktion standardkonform ist Dir& operator++( Dir& d ) { assert( d==EAST || d==NORTH || d==SOUTH ); if ( d == EAST ) d=NORTH; else if ( d == NORTH ) d=SOUTH; else if ( d == SOUTH ) d=WEST; return d; } .. for ( Dir i=START_DIR; i<END_DIR; ++i )
-
Badestrand schrieb:
Ich finde "Dummie"s Beispiel gut, Klassen finde ich hier vollkommenen Overkill.
Naja. Vielleicht für die For-Schleife schon noch gerade, aber man ist damit um einiges flexibler. Und inwiefern Overkill? Weil es einige Zeilen mehr Platz benötigt?
Vor allem kann man mit Klassen so etwas vermeiden (sofern man nicht
operator intüberlädt):Direction dir; int i = dir;Badestrand schrieb:
Dir& operator++( Dir& d ) { assert( d==EAST || d==NORTH || d==SOUTH ); if ( d == EAST ) d=NORTH; else if ( d == NORTH ) d=SOUTH; else if ( d == SOUTH ) d=WEST; return d; }Also ein
switchwäre hier wohl das Mindeste. Wobei ich sowieso Modulo und Cast anwenden würde. Und die Assertion bringt nur im Debug-Modus was, Exception wäre vielleicht besser.
-
Nexus schrieb:
Badestrand schrieb:
Ich finde "Dummie"s Beispiel gut, Klassen finde ich hier vollkommenen Overkill.
Naja. Vielleicht für die For-Schleife schon noch gerade, aber man ist damit um einiges flexibler. Und inwiefern Overkill? Weil es einige Zeilen mehr Platz benötigt?
Ja, alleine mit der Deklaration bist du bei 41 Zeilen, mit Definition vielleicht bei 200 (Leerzeilen mitgerechnet). Kann sein, dass ich gerade in einer Minimalismus-Phase bin oder hineinsteuere, aber wenn man mit einem Zehntel des Codes beinahe dasselbe erreichen kann, würde ich es vorziehen. Es ist nicht einmal die Wartung, die dürfte bei beiden Lösungen nahe 0 liegen. Es ist eher das Gesamtbild, also das schwierigere Hineinfinden in den Code, die erhöhte Dateienanzahl, die Übersicht leidet. Definitiv Geschmackssache, aber alles mit Klassen zu lösen (hier hat's auch Vorteile, keine Frage) ist halt nicht immer das Optimum.
Nexus schrieb:
Vor allem kann man mit Klassen so etwas vermeiden (sofern man nicht
operator intüberlädt):Direction dir; int i = dir;Hm, ich sehe nicht, wie man damit großartig Unfug anstellen könnte.
PS: Das Gefühl habe ich übrigens öfter, also dass bei "modernem"/"extrem sauberen" C++-Code so unglaublich viele Klassen und entsprechend Dateien und Codezeilen entstehen, dass m.M.n. viel an Übersicht verloren geht. Evtl bin ich im "Quellcode-Verstehen" unter'm Durchschnitt, aber wenn ich ein fremdes oder eigenes altes Projekt öffne und meine Augen 30 Klassen sehen, brauche ich etwas, um mich zurechtzufinden.
Selbiges bei Funktionen, oft wird stur ausgelagert, solange es geht. Mache ich eigentlich auch, als Regel hatte ich für mich auch mal, dass bei jedem Quelltext-Kommentar der darunterstehende Code in eine sprechende Funktion ausgelagert und der Kommentar damit überflüssig wird. Leider bringt jede zusätzliche Funktion auch zusätzlichen Denk-Overhead mit, schließlich muss man sie im Gesamtkontext einordnen und den Code-Zweck jedesmal neu erfassen. Bei einer 50-zeiligen Funktion ist die Funktion als Ganzes unübersichtlicher, dafür bleibt der Kontext, das Äußere übersichtlicher. Ohje, ich merke schon, mein Coding-Stil ist wohl gerade im Umbruch..
-
okay, ich hatte irgendwie gehofft, dass es da einen state of the art ansatz gäbe. an sich in ich mit beiden genannten lösungen zufrieden. mus smal schauen, ob und wie ich es nun angehe! ich dank eeuch schonmal an dieser stelle... die klasse ist natürlich absolut safe. zudem kann man konvertierungen in andere richtungsindizes recht schnell implementieren. allerdings habe ich etwas sorge, dass aufgrund der switch anweisungen etc. die laufzeit bei mir leiden koennte, denn es werden SEHR oft numerische einzeiler berechnugen in einer for schleife durchgeführt.
aber, wie gesagt, an sich find eich dir lösungen gut... jetzt muss ich mal schauen.danke und gute nach,
SirAnn
-
Badestrand schrieb:
Ohje, ich merke schon, mein Coding-Stil ist wohl gerade im Umbruch..

Du hast schon Recht. Normalerweise bin ich überhaupt nicht der Typ, der für alles gleich eine eigene Klasse schreibt, ich pack auch oft zu viel in eine Klasse (frag Dravere :D).
Und ja, es kommt halt immer drauf an, was man will. Wenn einem Typsicherheit oder Flexibilität (Erweiterbarkeit) wichtig ist, ist man mit einer Klasse besser beraten. Vor allem glaube ich nicht, dass diese Klasse in ein Umfeld von weiteren hunderten von Klassen platziert wird. Die Übersichtlichkeit sollte also nicht so stark gefährdet sein. Durch aussagekräftige Kommentare muss man den Header auch nicht erneut anschauen, um die Funktionsweise zu verstehen.
muffmolch schrieb:
allerdings habe ich etwas sorge, dass aufgrund der switch anweisungen etc. die laufzeit bei mir leiden koennte
switchist sehr effizient, da durch eine LookUp-Table schnell zur richtigen Marke gesprungen wird. Auch dadurch, dass eine Klasse um den Enum-Typen gebaut wird, sollte die Performance nicht wirklich eingeschränkt werden. Und wie gesagt wäre auch Modulo eine Lösung (bei der du weniger schreiben müsstest, aber vielleicht ist sie auch langsamer).Aber wenn es dir wirklich auf jede Mikrosekunde ankommt, solltest du mit einem Profiler herumexperimentieren, bevor du Schlüsse auf Performanceengpässe ziehst.
-
Nexus schrieb:
Aber wenn es dir wirklich auf jede Mikrosekunde ankommt, solltest du mit einem Profiler herumexperimentieren, bevor du Schlüsse auf Performanceengpässe ziehst.
das ist wohl wahr
war nur der erste Gedanke...