Ungarische Notation veraltet
-
Na was ist denn nun der Unterschied zwischen lptstrAngestellterName und AngestellterName? Der Mehrwert an nützlichen Infos hält sich doch arg in Grenzen ( = 0). Und ob eine Nullterminierte Zeichenkette erwartet wird kann man doch eigentlich auch am Aufbau der Funktion erkennen.
void Foo::SetzeName(char* AngestellterName) //kann ja nur Nullterminierte Zeichenkette erwarten, wie sollte man sonst das Ende der Zeichenkette erkennen? { } void Foo::SetzeName(char* AngestellterName, int Laenge) //Länge der Zeichenkette mit übergeben -> Nullterminierung nicht unbedingt notwendig { }
Vieleicht irre ich mich auch und die Logik ,die ich hinter dem obigen Code sehe, ist total falsch. Bitte flame't mich dann zu.
EDIT: Rechtschreibung++
-
Die ungarische Notation kannst du meines Wissens komplett vergessen.
-
wisser schrieb:
Die ungarische Notation kannst du meines Wissens komplett vergessen.
Das sehe ich auch so.
-
hehejo schrieb:
Ich bin auch von der Ungarischen Notation abgekommen.
A) Sind meine Funktionen überschaubar kurz
Nutze ich sprechende Variablennamen: Also z.B. AngestellterName statt m_wspzAname
C) Hab ich keine Probleme wenn sich der Typ meiner Variablen ändert. Gut mit passenden Refactoringmthoden kann ich schnell alle m_wspzAname in m_wspAname umändern - aber ich denke ihr wisst was ich meine.zu A): Funktionen können auch so überschaubar kurz sein - du musst ja nicht solch umständliche Präfixe wie 'm_wspz' wählen, was ich persönlich für viel zu lang halte. Bei mir hieße 'm_wspzAname' beispielsweise 'wName' (sofern sich die Klasse nur um den Angestellten dreht), ansonsten 'wEmployeeName' (ich bevorzuge Englisch :))
zu B): wie du unter A) siehst, funktioniert das auch mit Variablen, welche einen kleinen Typen-Präfix haben.
zu C): An sich hast du recht, man muss es überall ersetzen. Andererseits muss man in den meisten Fällen ohnehin den Code ändern, damit dieser mit dem neuen Typ funktioniert. Bei deinem Beispiel '_wspzAname' nach 'm_wspAname' gehe ich mal davon aus, dass du ein wchar_t* von einem nullterminierten String in einen nicht-nullterminierten String änderst. In dem Fall würden sämtliche Funktionen, welche die Nullterminierung erfordern, Probleme verursachen.
Ansonsten bieten die meisten IDEs inzwischen gute Suchen&Ersetzen-Funktionen an.Chris++ schrieb:
Na was ist denn nun der Unterschied zwischen lptstrAngestellterName und AngestellterName? Der Mehrwert an nützlichen Infos hält sich doch arg in Grenzen ( = 0). Und ob eine Nullterminierte Zeichenkette erwartet wird kann man doch eigentlich auch am Aufbau der Funktion erkennen.
void Foo::SetzeName(char* AngestellterName) //kann ja nur Nullterminierte Zeichenkette erwarten, wie sollte man sonst das Ende der Zeichenkette erkennen? { } void Foo::SetzeName(char* AngestellterName, int Laenge) //Länge der Zeichenkette mit übergeben -> Nullterminierung nicht unbedingt notwendig { }
Vieleicht irre ich mich auch und die Logik ,die ich hinter dem obigen Code sehe, ist total falsch. Bitte flame't mich dann zu.
EDIT: Rechtschreibung++
Oben ging es um die Variable einer Klasse, wodurch der Typ idR nur noch in der Header-Datei erkennbar ist. "AngestellterName" ist nun in sofern mehrdeutig, dass es ein char*, ein wchar_t*, std::string oder auch eine eigene Stringklasse sein kann.
-
Suchen und Ersetzen widerlegt jeglichen Sinn der Typkodierung in den Variablennamen, aber nur so am Rande.
Leute die den Typ in den Variablennamen einkodieren haben den Sinn von OOP oder generischer Programmierung nicht verstanden.
-
Das Thema interessiert mich schon lange und anscheinend sind hier viele Profis unterwegs. Folgendes Beispiel:
CString CStringName; BSTR BSTRName; MyCOMObject->get_Name(&BSTRName); CStringName = (LPCTSTR)BSTRName;
Wie markiert ihr gleiche Variablen mit unterschiedlichen Typen? Vor allem bei String, da es dort unzählige Varianten gibt.
-
CString getName() { BSTR name; MyCOMObject->get_Name(&name); return (LPCTSTR)name; }
-
Oben ging es um die Variable einer Klasse, wodurch der Typ idR nur noch in der Header-Datei erkennbar ist. "AngestellterName" ist nun in sofern mehrdeutig, dass es ein char*, ein wchar_t*, std::string oder auch eine eigene Stringklasse sein kann.
Wo ist da der Unterschied ?
std::string AngestellerNameA = "Mayer"; char* AngestellerNameB = "Mayer"; wchar_t* AngestellerNameC = "Mayer";
Wo ist da ein Unterschied ?
Anderes Beispiel:int counterA = 0; long counterB = 0; float counterC = 0; ... counterA++; counterC++; counterD++;
Wo ist da ein Unterschied ?
Beispiel mit Klassen/Struct:
struct LiedA { std::string album; std::string titel; LiedA(std::string album, std::string titel) { this->album = album; this->titel = titel; } std::string getAlbum() { return album; } std::string getTitel() { return titel; } } class LiedB { public: std::string album; std::string titel; LiedB(std::string album, std::string titel) { this->album = album; this->titel = titel; } std::string getAlbum() { return album; } std::string getTitel() { return titel; } }
Wozu muss ich jetzt wissen ob Lied eine Klasse oder Struktur ist ?
Funktionen können auch so überschaubar kurz sein - du musst ja nicht solch umständliche Präfixe wie 'm_wspz' wählen, was ich persönlich für viel zu lang halte. Bei mir hieße 'm_wspzAname' beispielsweise 'wName' (sofern sich die Klasse nur um den Angestellten dreht), ansonsten 'wEmployeeName' (ich bevorzuge Englisch )
Jetzt muss ich also mir nicht nur den Namen der Variable sondern auch ihren Type merken?
Statt einzutippen "coun" und die Autovervollständigung macht mir counterFürAlles,
muss ich
i_coun -> hmm da kommt nix
s_coun -> hmm da kommt auch nix
w_coun -> hmm da kommt wieder nix, welchen Type habe ich den gemacht ??
u_coun -> ahh endlich -> u_counterFürAllesWas ich damit sagen will: Ich will den Typen überhaupt nicht wissen. Wenn etwas falsch ist, dann meldet der Compiler! ein Fehler oder eine Warnung. Dafür ist der Compiler da. In C++ gibt es nicht umsonst Operatorüberladung damit Klassen sich wie Buildin-Typen anfühlen. Das ist eben einer der Vorteile von OOP-Sprachen wie C++, Java, C#, Ruby, usw.
-
DEvent schrieb:
int counterA = 0; long counterB = 0; float counterC = 0; ... counterA++; counterC++; counterD++;
Wo ist da ein Unterschied ?
Das ist einfach:
[cpp]
int counterA = 0;
long counterB = 0;
float counterC = 0;...
counterA++;
counterC++;
counterD++;[/cpp]SCNR
@electron, wenn du das nicht öfter machen musst, dann könnte man eine Funktion dafür auch weglassen und die Variablen einfach passend bennenen:
CString name; BSTR tempName; MyCOMObject->get_Name(&tempName); name = (LPCTSTR)tempName;
Jetzt ist sofort ersichtlich, dass BSTR nur dazu verwendet wird um den Namen zwischenzuspeichern und nach diesem Codeblock keine weitere Rolle mehr spielt.
Aber eine Funktion wie von :o vorgeschlagen ist natürlich zu Bevorzugen, wenn du das des öfteren machst.
-
Ergänzung:
Noch besser ist es natürlich sich strikt an RAII zu halten und das ganze zu folgendem zu vereinfachen:BSTR tempName; MyCOMObject->get_Name(&tempName); CString name = (LPCTSTR)tempName;
Aber all das hat man bei der Funktion von :o bereits, besser kann man es nicht machen.
-
DEvent schrieb:
std::string AngestellerNameA = "Mayer"; char* AngestellerNameB = "Mayer"; wchar_t* AngestellerNameC = "Mayer";
Wo ist da ein Unterschied ?
Die Definiton ist gleich, aber die Verwendung nicht.
Beispiel:if (AngestellerNameA1 == AngestellerNameA2) // gut ...; if (AngestellerNameB1 == AngestellerNameB2) // schlecht ...; if (AngestellerNameC1 == AngestellerNameC2) // schlecht ...;
-
Die ungarische Notation ist die taktische Nuklearwaffe im Kampf
gegen lesbaren Code - veraltet ist das falsche Wort, das war schon
von Anfang an ne schwachsinnige Idee...G,S
-
Sprengsatz schrieb:
Die ungarische Notation ist die taktische Nuklearwaffe im Kampf
gegen lesbaren Code - veraltet ist das falsche Wort, das war schon
von Anfang an ne schwachsinnige Idee...G,S
Amen.
MfG, total normal
-
Sprengsatz schrieb:
Die ungarische Notation ist die taktische Nuklearwaffe im Kampf
gegen lesbaren Code - veraltet ist das falsche Wort, das war schon
von Anfang an ne schwachsinnige Idee...G,S
Amen.
MfG, full ack
-
full ack schrieb:
Sprengsatz schrieb:
Die ungarische Notation ist die taktische Nuklearwaffe im Kampf
gegen lesbaren Code - veraltet ist das falsche Wort, das war schon
von Anfang an ne schwachsinnige Idee...G,S
Amen.
MfG, full ack
Ich wusste garnicht, dass es auch virtuelle Schatten wie dich gibt!
MfG, total normal
-
:o schrieb:
CString getName() { BSTR name; MyCOMObject->get_Name(&name); return (LPCTSTR)name; }
Dr. Prof schrieb:
Ergänzung:
Noch besser ist es natürlich sich strikt an RAII zu halten und das ganze zu folgendem zu vereinfachen:BSTR tempName; MyCOMObject->get_Name(&tempName); CString name = (LPCTSTR)tempName;
Aber all das hat man bei der Funktion von :o bereits, besser kann man es nicht machen.
Das diese Funktion eine Speicherleiche produziert ist euch hoffentlich klar.
-
Also auch auf die Gefahr hin, dass ich verkloppt werde, ich bin FÜR die ungarische Notation. Ich kann sie leider immer noch nicht zu 100%, da ich ein paar seltene Typen oft wieder vergesse, aber ansonsten probiere ich sie so oft wie möglich anzuwenden. Wieso?
1. Lesbarkeit. Genau das, wo so viele sagen, dass es nicht gefördert wird. Also ich weiss nicht aber ich kann einen Code der mit der ungarischen Notation versehen ist, deutlich schneller lesen und verstehen, als einer ohne. Wenn viele Variablen am Anfang einer grösseren Funktion deklariert werden oder in eine Klasse usw. dann kann ich mir nicht auswendig merken von welchem Typ jede Variable ist. Und ich will nicht immer mit der Maus über die Variable gehen, während dem Lesen um zu schauen von welchem Typ die ist.
2. Kürzere Variablen.
int nNamen;
Ist für mich klar, eine Anzahl Namen
int NamenCount;
Muss es mindestens ohne Notation heissen, denn unter Namen könnte man auch alles andere verstehen. Vielleicht eine Liste? Oder ein string mit Namen drin?
3. Variablennamen doppelt verwenden und trotzdem Klarheit. Zudem werden sie auch wie in 2. kürzer.
int nFirstAssist;
Nummer des FirstAssist Spielers.
CString strFirstAssist;
Name des FirstAssist Spielers.
4. Ich kann auch Quellcode als Text verschicken und darin ist dann auch noch klar, als was die Namen gemeint sind. Gerade für eine Dokumentation zu einem Quellcode, denke ich ist dies sehr angenehm.
5. Und ich wage nun sogar was ganz gemeines zu behaupten, damit man mich auch brav stark auseinander nimmt, ihr seid doch nur zu faul um die ungarische Notation zu lernen. Denn die Beispiele, welche hier teilweise aufgelistet wurden, waren manchmal sowas von schön. Klassen ohne Unterscheidung von privat, protected und public und so vereinfacht, wie wohl nie irgend eine Klasse aussehen wird. Klar sieht sie dann gleich aus wie eine Struktur und man fragt sich dann wieso sollte man nun ein C für Klassen verwenden und z.b. ein S für Strukturen. Die Sache ist aber die, dass halt Klassen oft komplexer sind und z.b. mehr Funktionen und solches Zeug anbieten, während eine Struktur oft nur eine Auflistung von verschiedenen Variablen ist ganz ohne Funktionen. Zudem ist es dann auch angenehmer und schneller zum unterscheiden zwischen Objekttyp und Variable.
Grüssli und viel Spass
-
Ich hab jetzt die letzten Seiten nur überflogen, doch ich glaube hier liegt ein grundlegendes Missverständnis in Sachen Ungarische Notation vor.
Die ursprüngliche Version der Hungarian Notation, die sog. Apps Hungarian wurde dafür entwickelt um eine Aussage über die Funktion der Variable zu machen und nicht über den Typen.
Die zweite Version, die auch in diesem Thread herumgeistert ist das Systems Hungarian, wo nur eine Aussage über den Datantypen mittels Präfix getroffen wird (manchmal zusätzliches noch ein Präfix für die Sichtbarkeit/static).
Ich weiß das, weil ich zufälligerweise vor kurzem ein Referat derüber in Softwareengingeering gehalten habe. Hier die Präsentation dazu:
-
Ich kann sie leider immer noch nicht zu 100%
Ähm, was gibt es da eigentlich groß zu lernen? 10min ne Tabelle (o.ä.) überfliegen und dann anwenden, das is kein Prozess von Wochen.
5. Und ich wage nun sogar was ganz gemeines zu behaupten, damit man mich auch brav stark auseinander nimmt, ihr seid doch nur zu faul um die ungarische Notation zu lernen.
Und ich behaupte das Gegenteil
Hab früher (Anfangszeiten) auch HN benutzt, aber einfach aus dem Grund heraus, weil ich zu FAUL war und es mir zu schwer viel mir RICHTIGE Namen für meine Valiablen auszudenken.Wenn du in C++ mit Klassen arbeitest, gibtst du den Objekten dann auch Präfixe, oder einen passenden Namen?
-
pZy schrieb:
Hab früher (Anfangszeiten) auch HN benutzt, aber einfach aus dem Grund heraus, weil ich zu FAUL war und es mir zu schwer viel mir RICHTIGE Namen für meine Valiablen auszudenken.
War bei mir auch so. Das habe ich mir dann aber abgewöhnt als mir nBuffer (für was???), m_sedtStartNr (oha...) zuviel wurde. Ausserdem sehe ich keinen Unterschied bzw. Vorteil der UN im nachfolgenden Code.
//UN if(bErgebnislisteGeladen) //ohne UN if(ErgebnislisteGeladen)
Jetzt mal im Ernst... Wo ist hier der Nutzen von "b..." und in welchem Fall ist das b gerechtfertigt? Ich sehe hier keinen (sinnvollen) Unterschied, ausser das das b... den Lesefluss stört. Da müsst ihr mir doch zustimmen oder?