Suche Liste mit "C++ Standardbezeichnungen"
-
Die wichtigste Regel ist: Sei konsistent. Erarbeite dir deine Regeln und bleibe dabei. Zumindest innerhalb desselben Projekts.
Und sei nicht zu originell, wenn du lesbar sein willst. Schau dir an, wie es andere Leute machen und kucke dir ab, was dir gefällt. Aber nimm dir nicht gerade die mitgelieferte STL-Implementierung als Beispiel
Stefan.
-
Naja, von ungarischer Notation halte ich ehrlich gesagt überhaupt nichts. Das geht ja noch gut in einfachen Sprachen, wo es ein paar wenige Typen gibt. Aber in C++ wird das recht schnell verwirrend.
int iVar; // int int* piVar; // Zeiger auf int int* apiVar[12]; // Array von Zeigern auf int? int* a12piVar[12]; // Man sollte die Dimension auch am Typ erkennen. class CMyClass {}; // Klasse struct SMyStruct {}; // Oder auch C? Semantisch werden class und struct oft unterschiedlich // angewandt, deshalb ein eigenes S gerechtfertigt? Und union? const CMyClass cVar; // Wie soll const angezeigt werden? Kleines c? const CMyClass& crefVar; // Const-Referenz? Und woher weiss man, dass es eine // Klasseninstanz ist? crefCVar? const CMyClass* const cpcCVar; // Const-Zeiger auf const MyClass - wie? char strVar[41]; // C-String, str liegt nahe. Oder Array deutlich machen? char* strVar; // Ebenfalls C-String, aber auch Zeiger auf char. std::string strVar; // Klasse. Sollte besser C sein. std::vector<std::string> astrVar; // a für Array, ähnlich wie std::vector. std::map<std::string> mstrVar; // Map ist vom Einsatz her ziemlich anders als Vector. // Ein eigenes Präfix wäre angebracht. float fVar; // Ziemlich eindeutig, dass hier f stehen muss. double dVar; // d? Oder für alle Fliesskommazahlen f? std::complex<float> cfVar; // c hat schon viele Bedeutungen. Oder einfach nur C für Klasse? // Jedoch ist eine komplexe Zahl ebenso eine Zahl wie float, // wieso sollte sie kein eigenes Präfix erhalten? CMyInt iVar; // Eigentlich Klasse - aber Verhalten genauso wie bei // int, dann wäre i-Präfix gerechtfertigt, oder? template <typename T, int N> class TVector {}; // Klassentemplates mit T, oder auch C? Den Unterschied // sollte man schon direkt am Bezeichner erkennen. TVector<double, 3> Td3Var; // Wie will man zeigen, dass es sich um ein Template mit Typ // double und Konstante 3 handelt? Das sollte verdeutlicht werden. typedef int Ffunc(double); // F für Funktionen - was ist mit Rückgabetyp und Parameter? typedef void (*pFv_idC_MyFunc)(int, double, CMyClass); // Funktionszeiger mit allen Informationen. typedef boost::function<int(double)> Fi_d_MyFunc; // Ist schliesslich semantisch auch eine Funktion. Andererseits // auch Klasse und Template - was jetzt? struct SMyFunctor {}; // Funktionsobjekt. S? C? Ist aber recht ähnlich wie Funktion.
Das mag vielleicht übertrieben erscheinen, aber genau darauf läuft es doch hinaus. Man stelle sich erst mal Kombinationen der einzelnen Typen vor - die Hölle persönlich. Du musst irgendwo willkürlich eine Grenze ziehen, nach der du den Typ nicht mehr genauer angibst. Und wieso sollten einige Informationen weniger wichtig sein als andere? Das kommt immer drauf an, wofür man etwas braucht. Du denkst jetzt vielleicht: "Ach was, für Klassen nehme ich einfach C, das reicht immer." In C++ sind extrem viele Typen Klassentypen. Gewinnt man da tatsächlich noch so viele Informationen daraus oder wird das C verwaschen? Meist kann man viel mehr durch ausdrucksstarke Bezeichner erreichen (z.B. durch Benennen von Klassen nach Substantiven und Funktionen nach Verben - so als grobe Leitlinie).
Was spricht dagegen, seine Variablen treffend nach ihrem Aufgabenbereich zu bezeichnen - also semantisch statt formal? Gerade in C++ hat man sehr viele Beispiele, wo sich nachgebaute Konstrukte wie BuiltIn-Typen verhalten. Was bringt dann eine künstliche Abgrenzung? Die Details der Deklaration stehen lange nicht immer im Vordergrund - vielmehr ist es wichtig, die vom Typ bereitgestellten Konzepte zu kennen (damit wären wir wieder bei
int
vs.MyInt
).Ich sehe eigentlich gar keinen Grund, den genauen Typen am Bezeichner abzulesen. Warum braucht man das angeblich so oft? Funktionen sollten im Idealfall eher klein sein, dann sind auch die Deklarationen gleich ersichtlich. Bei Klassen sagt ein Blick in die Headerdatei sowieso mehr als irreführende Präfixe. In modernen IDEs reicht ausserdem ein Darüberfahren mit der Maus, um den Deklarationstyp zu erkennen. Hingegen muss man mit der Ungarischen Notation beim Refactoring jeweils Bezeichner wechseln, wenn man doch einmal lieber Fliesskommazahlen statt Integers will.
Mir zumindest würde es so gehen, dass ich mich durch die UN stark eingeschränkt fühlte. Ich will doch nicht ständig diesem Zwang folgen, sowas wie
iCount
ist redundant. Aber manchmal hinschreiben und manchmal nicht ist noch viel schlimmer, weil es inkonsistent ist. Einzige "Ausnahme" ist bei mir ein Präfix, um Membervariablen zu kennzeichnen. Ganz nötig wäre es nicht, aber es ist praktisch, um zum Beispiel bei Settern Parameter und Member abzugrenzen, ohne immerthis->
zu schreiben. Ausserdem sagt es über den Typ selbst überhaupt nichts aus, ist also nicht direkt zu den oberen Beispielen vergleichbar (deshalb auch die Anführungszeichen bei Ausnahme).
-
-
...das sollte in die FAQ
-
Und dabei hat Nexus noch nicht einaml templates mit einbezogen. Wie soll man einen Template Parameter benennen, wo der Typ nicht einmal bekannt ist?
Im übrigen ist die ungarische Notation einfach ein Überbleibsel von Zeiten, wo die Leute noch in reinen Texteditoren programmiert haben. Da war das, denke ich sicher noch extrem hilfreich, aber Heute ist das imo einfach nur unnötig.
-
Nexus schrieb:
typedef int Ffunc(double); // F für Funktionen - was ist mit Rückgabetyp und Parameter? typedef void (*pFv_idC_MyFunc)(int, double, CMyClass); // Funktionszeiger mit allen Informationen. typedef boost::function<int(double)> Fi_d_MyFunc; // Ist schliesslich semantisch auch eine Funktion. Andererseits // auch Klasse und Template - was jetzt? struct SMyFunctor {}; // Funktionsobjekt. S? C? Ist aber recht ähnlich wie Funktion.
Befürworter der Ungarischen Notation haben dieses Problem nicht, da ihr C++ stilistisch irgendwo vor 1996 stattfindet.
-
Danke für die Zustimmung.
Hm, Fragen bezüglich Ungarischer Notation treten hier schon ab und zu auf, aber ob die einen FAQ-Eintrag wert sind? Dort gibts schon genügend unwichtige Themen. Andererseits könnte man auch argumentieren, dass UN genau deshalb einen Eintrag verdient hätte.
Ich denke, ansonsten kann man diesen Thread auch verlinken...
-
Mehr als "UN ist doof" braucht man nicht zu wissen. Und das erfährt man auch ohne FAQ schnell genug.
-
volkard schrieb:
Mehr als "UN ist doof" braucht man nicht zu wissen.
Alter Dokmatiker.
-
Bashar schrieb:
volkard schrieb:
Mehr als "UN ist doof" braucht man nicht zu wissen.
Alter Dokmatiker.
Wo er Recht hat ...
-
Bashar schrieb:
volkard schrieb:
Mehr als "UN ist doof" braucht man nicht zu wissen.
Alter Dokmatiker.
hihi.
Wie immer gibt es Ausnahmen. So ist zum Beispiel manchmal das p vor bedeutungslosen Zeigern gut,if(*pa<*pb)//ohne schutz schreibt man dauend if(pa<pb) foo(pa); else foo(pb);
-
Wenn die Zeiger bedeutungslos sind, ist es der Code sicher auch. Dann kommt es auch nicht mehr aufs Dereferenzieren an ...
-
camper schrieb:
Wenn die Zeiger bedeutungslos sind, ist es der Code sicher auch. Dann kommt es auch nicht mehr aufs Dereferenzieren an ...
damit meine ich, daß sie nicht file, dog oder avlTreeNode heißen, sondern die funktion eher eine universelle funktion ist, die zum beispiel auf allen zeigerpaaren operieren kann, wenn die pointees vergleichbar sind.
template<typename T> void deleteTheBiggerOne(T* pa,T* pb){ if(... ... }