Hallo mal wieder!
Ich tue mir manchmal schwer, ordentliche Klassennamen auszuwählen,
Beispiel Ethernet:
Habe verschiedene Dateien angelegt mit dem namen der verschiedenen
Protokolle, bspws. arp.cpp, dhcp.cpp, ipv4.cpp, etc. Dort befinden sich
jeweils die Klassen ARP, DHCP, IPV4, etc.
Nun arbeite ich damit auf einem µC und habe somit noch verschiedene
Methoden um den Ethernet MAC+DMA zu konfigurieren. Diese habe ich unter
ethernet_hw.cpp abgelebt in eine Klasse Namens HW_LAYER.
Soweit könnte ich noch mit leben, wobei mir hier schon das HW_LAYER
aufstößt. Schlimmer wird die Verbindung zwischen diesem HW_LAYER und den
Protokoll-Klassen. Da mir nichts besseres eingefallen ist, habe ich sie
mal SW_LAYER genannt.
Habt ihr auch manchmal solche Probleme wie ich :)
Wie handhabt ihr sowas? Googelt ihr irgendwie nach passenden Begriffen?
Oder habt ihr so einen großen Wortschatz bzw. Erfahrung?
Und: Schaut ihr, dass die Klassenmethoden absolut zu der Klasse passen,
oder wird da auch mal ein klein wenig was vermischt?
Grüße
Reggie
Variablen- und auch Klassennamen sollte man keinesfalls in Versalien
(d.h. komplett in Großbuchstaben) schreiben. Die Konvention reserviert
das für Macros (d.h. #defines).
Reginald L. schrieb:> Habt ihr auch manchmal solche Probleme wie ich :)> Wie handhabt ihr sowas? Googelt ihr irgendwie nach passenden Begriffen?> Oder habt ihr so einen großen Wortschatz bzw. Erfahrung?
Nein. Typischer Weise fängt man damit an, einer Klasse eine eng
umrissene Aufgabe zu geben und dann drängt sich der Name schon etwas
auf. Namespaces können helfen, gute Namen in verschiedenen Kontexten zu
verwenden.
> Und: Schaut ihr, dass die Klassenmethoden absolut zu der Klasse passen,> oder wird da auch mal ein klein wenig was vermischt?
C++ ist nicht Java. Es gibt also keinen Zwang, jede Funktion in einer
Klasse unterbringen zu müssen oder jede kleinste Klasse in einem eigenen
Header zu deklarieren.
mfg Torsten
Rufus Τ. F. schrieb:> Die Konvention reserviert> das für Macros (d.h. #defines).
Ah OK, ich vermute mal, sich an solche Konventionen zu halten macht
Sinn, auch, wenn das Programm nur für Hobbyzwecke genutzt wird und
ausser mir den Code niemand sieht.
Torsten R. schrieb:> Nein. Typischer Weise fängt man damit an, einer Klasse eine eng> umrissene Aufgabe zu geben und dann drängt sich der Name schon etwas> auf. Namespaces können helfen, gute Namen in verschiedenen Kontexten zu> verwenden.
Das habe ich doch gemacht oder siehst du das anders?
Namespaces vergebe ich auch, obwohl das alles irgendwie noch unklarer
wird. Beispielsweise steckt alles was mit dem Ethernet zu tun hat im
Namespace Ethernet. Die Protokolle stecken zusätzlich im Namespace
Protocol. Dazu noch eine Frage: Wann und wie sollte man "using namespace
xy" verwenden? Bei einer größeren Anzahl Zugriffe auf diese?
Torsten R. schrieb:> Es gibt also keinen Zwang, jede Funktion in einer> Klasse unterbringen zu müssen oder jede kleinste Klasse in einem eigenen> Header zu deklarieren.
Ja, mir fehlt da leider die Theorie und Erfahrung. Programmiere ja noch
nicht so lange. Diesbezüglich gibt es auch recht wenig zu finden im
Internet.
Reginald L. schrieb:> Namespaces vergebe ich auch, obwohl das alles irgendwie noch unklarer> wird. Beispielsweise steckt alles was mit dem Ethernet zu tun hat im> Namespace Ethernet. Die Protokolle stecken zusätzlich im Namespace> Protocol.
Kann man machen. Ich nehme normalerweise einen Namespace für meinen
Namen (DPA), und einen für mein (Teil)projekt, z.B. UCS. Andere können
Dinge dann mit DPA::UCS::Klassename verwenden, und innerhalb vom
(Teil)Projekt bin ich überall im gleichen Namespace. Eventuell muss ich
auf andere Teilprojekte zugreifen, z.B. Utility::memrcpy, etc. "using
namespace" verwende ich fast nie, nichteinmal bei std.
Reginald L. schrieb:> Rufus Τ. F. schrieb:>> Die Konvention reserviert>> das für Macros (d.h. #defines).> Ah OK, ich vermute mal, sich an solche Konventionen zu halten macht> Sinn, auch, wenn das Programm nur für Hobbyzwecke genutzt wird und> ausser mir den Code niemand sieht.
Sagen wir mal so: Es hat in der Regel keinen besonderen Nachteil, sich
daran zu halten.
> Torsten R. schrieb:>> Nein. Typischer Weise fängt man damit an, einer Klasse eine eng>> umrissene Aufgabe zu geben und dann drängt sich der Name schon etwas>> auf. Namespaces können helfen, gute Namen in verschiedenen Kontexten zu>> verwenden.> Das habe ich doch gemacht oder siehst du das anders?
Es hört sich ein bisschen an, als hättest du alles, was noch nicht
irgendwo anders untergebracht ist und von dem du nicht weißt, wohin
damit, in dein HW_LAYER gesteckt. Deshalb fällt dir dann schwer, es
richtig zu benennen.
> Namespaces vergebe ich auch, obwohl das alles irgendwie noch unklarer> wird. Beispielsweise steckt alles was mit dem Ethernet zu tun hat im> Namespace Ethernet. Die Protokolle stecken zusätzlich im Namespace> Protocol. Dazu noch eine Frage: Wann und wie sollte man "using namespace> xy" verwenden? Bei einer größeren Anzahl Zugriffe auf diese?
Von "using namespace" wird meist eher abgeraten. Manche qualifizieren
die Namen aus dem Namespace bei jeder Benutzung explizit, adere
verwenden using-Deklarationen um gezielt die benutzten Namen
reinzuholen. Letzteres hat den Vorteil, wenn man mal z.B. eine Klasse in
zwei Varianten hat, die in unterschiedlichen Namespaces liegen, dass man
nur eine Stelle modifizieren muss. Kommt aber in der Praxis kaum vor.
Wo man grundsätzlich auf "using namespace" verzichten sollte, sind
Header.
Und wie handhabt ihr es weiters mit der Variablennamensgebung?
1
classInitStatus
2
{
3
...
4
}
5
6
classStartUp
7
{
8
....
9
public:
10
InitStatusinitstatus;
11
}
Hier habe ich auch immer meine Probleme einen "gscheiten" Namen zu
definieren. Ich möchte ja in einer Methode auf etwas zugreifen, das
einen klaren Namen hat. Wie aber soll ich dann die Klasse "InitStatus"
nennen? Die Leute von ST, auch wenn sie es in plain-C machen, benutzen
für sowas "xyTypeDef". Ist so etwas ratsam? Wie handhabt ihr solche
Namensgebungen?
Reginald L. schrieb:> Hier habe ich auch immer meine Probleme einen "gscheiten" Namen zu> definieren. Ich möchte ja in einer Methode auf etwas zugreifen, das> einen klaren Namen hat. Wie aber soll ich dann die Klasse "InitStatus"> nennen?
kein Mensch kann (sollte) Dir einen Namen nennen, wenn Du uns nicht
sagst, was das "Ding" machen soll. Fang einfach bei den Anforderungen
an. Wenn sich daraus ergibt, dass irgend etwas in Stufen / Etappen
initialisiert werden muss, dann kann es sein, dass eine Klasse oder ein
Aufzählungstyp dafür sinnvoll ist. Aber ohne Anforderungen, kein Design.
> Die Leute von ST, auch wenn sie es in plain-C machen, benutzen> für sowas "xyTypeDef". Ist so etwas ratsam? Wie handhabt ihr solche> Namensgebungen?
Ich bevorzuge den stil, den die C++ libraries oder boost verwenden (das
wäre dann "init_status", "startup"). Wenn ich aber sehr große
Bibliotheken, wie Qt benutzen würde, würde ich deren Namenkonventionen
übernehmen, damit es ein stimmiges Gesamtbild ergibt).
Namespace würde ich auch nicht überbewerten, wenn Du nur für den
Privat-Gebrauch entwickelst, wirst Du sie wahrscheinlich nicht brauchen.
Wenn alle Dinge im Projekt auch ohne namespaces gute Namen bekommen
können, dann würde ich keine verwenden.
mfg Torsten
p.s. Ich würde mich auf keinen Fall bei Software-Entwicklung an ST
orientieren.
Torsten R. schrieb:> kein Mensch kann (sollte) Dir einen Namen nennen, wenn Du uns nicht> sagst, was das "Ding" machen soll. Fang einfach bei den Anforderungen> an. Wenn sich daraus ergibt, dass irgend etwas in Stufen / Etappen> initialisiert werden muss, dann kann es sein, dass eine Klasse oder ein> Aufzählungstyp dafür sinnvoll ist. Aber ohne Anforderungen, kein Design.
Zu obigem Bsp: InitStatus zeigt mir welche Systeme initialisiert wurden
und welche nicht, sie enthält in dem Fall nur bool's die man re-/setten
kann. Für den Klassennamen habe ich mir somit InitStatus überlegt. Nun
möchte ich diese Klasse in einer anderen verwenden. Also deklariere ich
mit InitStatus initstatus. Diese doppelten Namen, auch wenn farblich
ersichtlich ob es sich um ne Klasse oder Klasseninstanz handelt, sind
doch irgendwie seltsam. Ist das nunmal so oder wie würdest du, in so
einem Fall vorgehen?
Torsten R. schrieb:> Ich bevorzuge den stil, den die C++ libraries oder boost verwenden (das> wäre dann "init_status", "startup")
Bezieht sich das auf die obige Fragestellung? Also im Prinzip würdest du
auch die Klasse InitStatus und eine Instanz davon init_status nennen?
Torsten R. schrieb:> Namespace würde ich auch nicht überbewerten, wenn Du nur für den> Privat-Gebrauch entwickelst, wirst Du sie wahrscheinlich nicht brauchen.> Wenn alle Dinge im Projekt auch ohne namespaces gute Namen bekommen> können, dann würde ich keine verwenden.
Wobei es schon praktisch ist, das ganze Zeug das zu einer Kategorie
gehört unter einem Namen laufen zu haben. Ansonsten kriegt man u.U. ja
zig-Tausende Zeilen Code in einer Datei. Partielle Klassen sind ja,
soweit ich weiß, in C++ nicht möglich.
Reginald L. schrieb:> Zu obigem Bsp: InitStatus zeigt mir welche Systeme initialisiert wurden> und welche nicht, sie enthält in dem Fall nur bool's die man re-/setten> kann.
Was ist der tiefere Sinn dahinter? Wer verwendet diese Information?
Reginald L. schrieb:> Zu obigem Bsp: InitStatus zeigt mir welche Systeme initialisiert wurden> und welche nicht, sie enthält in dem Fall nur bool's die man re-/setten> kann.
Dann nimm isInitialized, liest sich dann besser:
Torsten R. schrieb:> kein Mensch kann (sollte) Dir einen Namen nennen, wenn Du uns nicht> sagst, was das "Ding" machen soll. Fang einfach bei den Anforderungen> an. Wenn sich daraus ergibt, dass irgend etwas in Stufen / Etappen> initialisiert werden muss, dann kann es sein, dass eine Klasse oder ein> Aufzählungstyp dafür sinnvoll ist. Aber ohne Anforderungen, kein Design.
Genau so ist es. Generell kann man
1.) für Daten die Frage stellen:
Was genau sollen diese darstellen? Daraus leitet sich der Name ab, den
man den dazugehörigen Strukturen gibt (Variablen, Objekte etc.)
2.) für Code die Frage stellen:
Was genau soll dieser tun? Daraus leitet sich der Name ab, den die
entsprechenden Funktionen oder Klassenmethoden haben.
Reginald L. schrieb:> ... Diese doppelten Namen, auch wenn farblich> ersichtlich ob es sich um ne Klasse oder Klasseninstanz handelt, sind> doch irgendwie seltsam. Ist das nunmal so oder wie würdest du, in so> einem Fall vorgehen?
1
library_set initialized_libraries_;
Code sollte meiner Meinung nach auch ohne Code-Highlighting lesbar sein.
Allerdings sollte man schon voraussetzen dürfen, dass der Leser weis,
dass vor dem Namen eines Objekts der Type des Objekts steht.
Überlicherweise beschreibt der Type was etas ist, daraus ergibt sich
auch, welche Operationen auf das Objekt zu erwarten sind. Der Name des
Objekts sollte dann die Rolle bestimmen:
1
std::vector< std::string > books_read; // not book_vector
2
int number_of_days_till_christmas; // not i
3
std::string text; // not str
>> Torsten R. schrieb:>> Ich bevorzuge den stil, den die C++ libraries oder boost verwenden (das>> wäre dann "init_status", "startup")> Bezieht sich das auf die obige Fragestellung? Also im Prinzip würdest du> auch die Klasse InitStatus und eine Instanz davon init_status nennen?
Nein. Ich würde eine Klasse immer "init_status" nennen, weil es so in
Boost oder der C++ library benannt werden würde.
>> Torsten R. schrieb:>> Namespace würde ich auch nicht überbewerten, wenn Du nur für den>> Privat-Gebrauch entwickelst, wirst Du sie wahrscheinlich nicht brauchen.>> Wenn alle Dinge im Projekt auch ohne namespaces gute Namen bekommen>> können, dann würde ich keine verwenden.> Wobei es schon praktisch ist, das ganze Zeug das zu einer Kategorie> gehört unter einem Namen laufen zu haben. Ansonsten kriegt man u.U. ja> zig-Tausende Zeilen Code in einer Datei.
Äh....?!?, Du kannst namespaces gut zum gruppieren verwenden, wenn dann
aber jede Gruppe eh nur 20 Mitglieder hat, dann wird es überflüssig
(network::tcp_socket, gui::button, etc.) Es gibt aber auch keinen
Zusammenhang zu Dateigrößen. Du darfst auch ohne namespaces eine zweite
Datei verwenden ;-)
> Partielle Klassen sind ja,> soweit ich weiß, in C++ nicht möglich.
Habe ich auch noch nie vermisst.
Fritz G. schrieb:> Dann nimm isInitialized, liest sich dann besser:> if (isInitialized) {> ...> }
HA! Top! ->
1
classINITSTATUS
2
{
3
public:
4
...
5
};
6
7
classSTARTUP
8
{
9
public:
10
staticINITSTATUSisInitialized;
11
};
So finde ich das prima. Ich glaube da fehlt mir einfach die Praxis.
Torsten R. schrieb:> std::vector< std::string > books_read; // not book_vector> int number_of_days_till_christmas; // not i> std::string text; // not str
Daraus schließe ich, dass die obige Aufführung also richtig ist.
Torsten R. schrieb:> Nein. Ich würde eine Klasse immer "init_status" nennen, weil es so in> Boost oder der C++ library benannt werden würde.
Ja ok, in C# habe ich da auch keine Probleme mit.
Ich schließe daraus, dass ich einfach mal "tiefer" denken muss :>
Reginald L. schrieb:> OK, ich glaube ich werde mal konkreter:
das ist vielleicht konkreter, aber nicht aufschlussreicher ;-)
> Ich schließe daraus, dass ich einfach mal "tiefer" denken muss :>
Oder bei den Anforderungen anfangen. Welche Anforderungen hast Du, die
Dich auf die Idee bringen, dass eine Klasse mit einem Sack voll
öffentlicher booleans die Lösung dazu wäre? ;-)
Torsten R. schrieb:> Oder bei den Anforderungen anfangen. Welche Anforderungen hast Du, die> Dich auf die Idee bringen, dass eine Klasse mit einem Sack voll> öffentlicher booleans die Lösung dazu wäre? ;-)
Also mein Gedanke war Folgender:
Wenn das System hochfährt und eine Initialisierung fehlschlägt soll mir
ausgeprintf't werden, welche Initialisierung fehlgeschlagen hat. Um die
Initialisierungsroutine übersichtlich zu halten, wird nach jedem
Teilsystem-Init geprüft ob alles OK ist, falls nicht, wird SetError()
ausgeführt. Das sah für mich nach der einfachsten Methode aus. Ansonsten
müsste ich für jedes Teilsystem-Init eine eigene SetErrorXY()-Methode
ausführen.
Wenn jetzt ein Teilsystem dazukommt, brauche ich nur eine Variable in
die Klasse INITSTATUS einzufügen und ein printf hinzufügen. Und
natürlich die bool'sche Variable auf true setzen.
Mir gefällt das auch nicht wirklich, aber ich komme einfach nicht auf
was anderes. Und wenn du wüsstest wie oft ich das verändert habe und wie
das zu Anfang aussah :) Dann wärst du stolz auf mich :>
EDIT:
Hier noch die Initroutine. Die bool'sche Variable wird in den
Teilsystem-Inits() auf true gesetzt.
Torsten R. schrieb:> Namespace würde ich auch nicht überbewerten, wenn Du nur für den> Privat-Gebrauch entwickelst, wirst Du sie wahrscheinlich nicht brauchen.> Wenn alle Dinge im Projekt auch ohne namespaces gute Namen bekommen> können, dann würde ich keine verwenden.
Ich finde sie ganz praktisch, um nicht so arg lange Namen zu bekommen.
In C passiert das schon mal, wenn man für alles einen Prefix schreibt.
Den kann man in C++ dann durch einen Namespace erstezen.
Reginald L. schrieb:> Zu obigem Bsp: InitStatus zeigt mir welche Systeme initialisiert wurden> und welche nicht, sie enthält in dem Fall nur bool's die man re-/setten> kann.
Ich würde sie vermutlich eher SystemStatus nennen. Aber warum enthält
nicht jedes System seinen Status selber? Da würde er für mich eher
hingehören. Oder hattest du nicht für jedes dieser Systeme eine Klasse
vorgesehen?
> Torsten R. schrieb:> Wobei es schon praktisch ist, das ganze Zeug das zu einer Kategorie> gehört unter einem Namen laufen zu haben. Ansonsten kriegt man u.U. ja> zig-Tausende Zeilen Code in einer Datei. Partielle Klassen sind ja,> soweit ich weiß, in C++ nicht möglich.
Das verstehe ich nicht. Was hat die Größe der Quellcode-Dateien mit der
Benutzung von Namespaces zu tun?
Reginald L. schrieb:> class STARTUP
Das gefällt mir als Name nicht. Der Klassenname sollten immer ein
Substantiv sein, das beschreibt, was eine Instanz der Klasse darstellt.
Was ist ein "STARTUP"?
Rolf M. schrieb:> Ich würde sie vermutlich eher SystemStatus nennen. Aber warum enthält> nicht jedes System seinen Status selber? Da würde er für mich eher> hingehören. Oder hattest du nicht für jedes dieser Systeme eine Klasse> vorgesehen?
Das habe ich absichtlich nicht gemacht, um die Teilsystemklassen
übersichtlicher zu halten. Hinzu kommt, dass ich dann ja trotzdem
irgendwo eine Klasse haben muss, die diese Status"e" "überwacht" bzw.
aufsammelt und auswertet.
Aber eigentlich ging es mir ja bei dem Thread eher um den
Klasseninstanznamen. Das hat sich also eigentlich schon erledigt :)
Rolf M. schrieb:> Das verstehe ich nicht. Was hat die Größe der Quellcode-Dateien mit der> Benutzung von Namespaces zu tun?
Damit wollte ich auf nested classes hinaus. Falls man ein komplettes
(Teil-)System unter einem "Namen" haben möchte.
Rolf M. schrieb:> Der Klassenname sollten immer ein> Substantiv sein, das beschreibt, was eine Instanz der Klasse darstellt.
Aha! Gut zu wissen. Werde ich drauf achten. Mir hat das STARTUP auch nie
gefallen.
Rolf M. schrieb:>> Torsten R. schrieb:>> Wobei es schon praktisch ist, das ganze Zeug das zu einer Kategorie>> gehört unter einem Namen laufen zu haben. Ansonsten kriegt man u.U. ja>> zig-Tausende Zeilen Code in einer Datei. Partielle Klassen sind ja,>> soweit ich weiß, in C++ nicht möglich.
Verleumdung!!!! ;-)
Reginald L. schrieb:> Aber eigentlich ging es mir ja bei dem Thread eher um den> Klasseninstanznamen. Das hat sich also eigentlich schon erledigt :)
Es kann aber auch ein guter Hinweis sein, dass etwas mit dem Design
nicht stimmt, wenn man einfach keinen guten Namen findet.
Torsten R. schrieb:> Reginald L. schrieb:> Aber eigentlich ging es mir ja bei dem Thread eher um den> Klasseninstanznamen. Das hat sich also eigentlich schon erledigt :)>> Es kann aber auch ein guter Hinweis sein, dass etwas mit dem Design> nicht stimmt, wenn man einfach keinen guten Namen findet.
Die Lösung War doch Top :)
Hoffe nur, dass mir iwann solche Sachen auch selber einfallen.
Reginald L. schrieb:> static INITSTATUS InitStatus;
Tu dir einen Gefallen, mache es nicht so.
Die Klasse: InitStatus (grosser Anfangsbuchstabe)
Die Variable: initStatus (kleiner Anfangsbuchstabe)
So weisst du später im Code ob du mit der Klasse oder der Instanz
arbeitest.
Beispiel:
Hier siehst du auch die sprechenden Namen. Keine Scheu vor langen Namen,
bei vernünftigen IDEs brauchst du nur ein paar Buchstaben tippen und dir
werden die richtigen Möglichkeiten vorgeschlagen.
Zu deinem Beispiel wo du konkreter wirst:
Gross-/ Kleinschreibung wurde ja schon gesagt
Deine "Klasse" INITSTATUS enthält nur Daten, aber keine Methoden um sie
zu verändern. Ich würde diese deshalb als struct deklarieren (Ja in C++
ist der Unterschied struct <-> class klein, dem Verständnis hilft es
aber diese zu unterscheiden)
Die Funktion SetError() verändert augenscheinlich keine Daten sondern
schreibt sie nur auf die Konsole. Das Set sollte also Print heissen.
Zudem sind es keine Errors die gedruckt werden, sondern Status
-> printStatus() wäre vermutlich klarer, was die Funktion macht.
Reginald L. schrieb:> Die Lösung War doch Top :)
Mit Verlaub, aber vielleicht ist Dein Software-Design immer noch Grütze
und Du merkst es bloß nicht. ;)
Reginald L. schrieb:> Torsten R. schrieb:>> Oder bei den Anforderungen anfangen. Welche Anforderungen hast Du, die>> Dich auf die Idee bringen, dass eine Klasse mit einem Sack voll>> öffentlicher booleans die Lösung dazu wäre? ;-)> Also mein Gedanke war Folgender:> Wenn das System hochfährt und eine Initialisierung fehlschlägt soll mir> ausgeprintf't werden, welche Initialisierung fehlgeschlagen hat. Um die> Initialisierungsroutine übersichtlich zu halten, wird nach jedem> Teilsystem-Init geprüft ob alles OK ist, falls nicht, wird SetError()> ausgeführt. Das sah für mich nach der einfachsten Methode aus. Ansonsten> müsste ich für jedes Teilsystem-Init eine eigene SetErrorXY()-Methode> ausführen.> Wenn jetzt ein Teilsystem dazukommt, brauche ich nur eine Variable in> die Klasse INITSTATUS einzufügen und ein printf hinzufügen. Und> natürlich die bool'sche Variable auf true setzen.
Ich würde hier eine Art Supervisor-Klasse vorschlagen. Diese fragt den
Status aller Subsysteme ab. Außerdem ist sie dafür zuständig,
entsprechende Fehlermeldungen zu generieren und eventuell
Ausfallreaktionen einzuleiten.
Und in gar keinem Fall braucht man dafür public bool Variablen. ;-)
Reginald L. schrieb:> Also mein Gedanke war Folgender:> Wenn das System hochfährt und eine Initialisierung fehlschlägt soll mir> ausgeprintf't werden, welche Initialisierung fehlgeschlagen hat.
Nah, wo liegt denn das Problem? Jedes Sub-system hat also eine
initialize() Funktion/Methode, die TRUE oder FALSE zurückliefert.