Archiv verlassen und diese Seite im Standarddesign anzeigen : C++-Anfänger braucht Stilempfehlung für Strings in Klassen
McFraggle
04-08-2010, 11:57
Hallo miteinander. Habe eine Frage, da mir noch der Weit- und Durchblick für C++, insbesondere für Zeiger und Refenzen im Umgang mit Objekten fehlt.
Man stelle sich eine einfache Klasse Person vor, welche nur ein privates Feld name vom Typ std::string hat. Trivial, gel?
Für den Namen gibt es nun den üblichen Getter und Setter. Die Klasse Person hat zudem einen Konstruktor um das Feld zu initialisieren, also Person::Person(std::string name) und einen leeren Konstruktor, der das Feld mit einem Leerstring initialisiert.
Dabei wünsche ich mir als Klassenentwickler natürlich
einfache Handhabung für den Nutzer der Klasse
das String-Objekt sollte mit dem entsprechenden Personen-Objekt zerstört werden
Die Frage:
Welchen Typ nehme ich für das lokale Feld name? Einfach string oder string* oder string& ? Bei meinen bisherigen Experimenten funktionierte nur die Zeigervariante. Die native Form (kein Zeiger, keine Referenz) machte Ärger bei der Initialisierung im leeren Konstruktor. Eventuell wurde das String-Objekt nach verlassen des Konstruktor-Scopes aufgelöst und meine Objektvariable zeigte in ungenutzten Speicher ... keine Ahnung. Bei einem Zeiger ist die Verwendung für den Anwender aber hackelig. Da wären mir Referenzen lieber.
Also: wie macht Ihr das? Ein C++-String als Objektvariable? Nativ, als Zeiger, als Referenz? Konvertieren Setter, Getter oder Konstruktoren den Typ (dereferenzieren, etc...)?
Danke für alle Hinweise, Warnungen, Erfahrungen und mir unbekannte „best practices“! :)
peschmae
04-08-2010, 15:31
Ich würde das als normale Member-Variable machen. Worin genau bestehen denn deine Initialisierungsprobleme? Kurzcodebeispiel?
MfG Peschmä
McFraggle
04-08-2010, 18:51
Hi und danke schon mal.
Also:
Ich habe meinen Anwendungsfall mittlerweile auch mit einer einfachen Membervariable realisiert. Das Initialisierungsproblem kann abgehakt werden. Das Problem war ein ganz anderes: C++ erlaubt keine verschachtelten Konstruktoraufrufe, und solche hatte ich verwendet. Nur hat mich der Fehler-Phänotyp irritiert: In Konstruktor A hatte ich beim Versuch Konstruktor B aufzurufen ein neues Objekt erzeugt, welches mit dem Ende von Konstrukor A wieder verschwand. Die Membervariable des äußeren Objektes blieb natürlich unberührt und so sah es für mich einfach danach aus, als sei das String-Objekt wieder „verschwunden“.
Nun ja, dennoch bleibt eine Frage:
Der Getter ist bei mir nun vom Typ string und wie ich bemerkte, legt C++ bei der Rückgabe durch den Getter eine Kopie meiner Membervariable an. Möchte man jedoch direkt das String-Objekt durch den Getter zurückgeben, bleibt mir nix anderes als den Rückgabetyp auf string* zu ändern und die Adresse meiner Membervariable zurückzugeben; Ist das richtig?
Wie machen das C++-Entwickler gewöhnlich? Im Getter Kopien oder Zeiger zurückgeben? Oder ist das ein beliebiges Durcheinander? Gibt's da (Namens-)Konventionen?
Und noch eine Frage:
Wie handhabt C++ das bei anderen (eigenen) Objekttypen? Werden da auch Kopien erzeugt? Bin ich daher genötigt, immer Copy-Konstruktoren zu schreiben? Falls nicht: handelt es sich dann immer um flache Kopien?
Danke für weitere Aufklärung!
Ein Java-Verdorbener... :)
sommerfee
04-08-2010, 19:12
Nur hat mich der Fehler-Phänotyp irritiert: In Konstruktor A hatte ich beim Versuch Konstruktor B aufzurufen ein neues Objekt erzeugt, welches mit dem Ende von Konstrukor A wieder verschwand. Die Membervariable des äußeren Objektes blieb natürlich unberührt und so sah es für mich einfach danach aus, als sei das String-Objekt wieder „verschwunden“.
Das ist richtig so. Person(...) erzeugt eine (neue) Instanz von Person auf dem Stack, wie z.B. in "Person x = Person(...);".
Java kann es sich hier erlauben, stattdessen den Konstruktor aufzurufen, weil es keine Instanzen auf dem Stack kennt, und daher Instanzen grundsätzlich mit "new" erzeugt werden müssen. (In C++ ist die von Java bekannte Notation aber bereits anderweitig belegt, siehe oben.)
Der Getter ist bei mir nun vom Typ string und wie ich bemerkte, legt C++ bei der Rückgabe durch den Getter eine Kopie meiner Membervariable an. Möchte man jedoch direkt das String-Objekt durch den Getter zurückgeben, bleibt mir nix anderes als den Rückgabetyp auf string* zu ändern und die Adresse meiner Membervariable zurückzugeben; Ist das richtig?
Ich persönlich würde "const string&" zurückgeben. Das kann man direkt verwenden, ohne daß eine Kopie angelegt wird, man kann aber auch durch Zuweisung eine Kopie anlegen, wenn gewünscht.
Wie handhabt C++ das bei anderen (eigenen) Objekttypen?
C++ hat im Gegensatz zu Java keine eigenen Objekttypen.
Bin ich daher genötigt, immer Copy-Konstruktoren zu schreiben?
Wenn der implizit erzeugte Copy-Konstruktor ein Problem erzeugen würde (z.B. ein Speicherleck), ja, dann sollte man einen eigenen schreiben. Wenn man grundsätzlich keine Kopien braucht, würde ich den sicherheitshalber trotzdem (als leere Hülle) schreiben, und zwar als "private" deklariert, damit der Compiler bei der Verwendung eine Fehlermeldung wirft. (Gleiches gilt für operator=).
Liebe Grüße,
Axel
McFraggle
04-08-2010, 19:41
Hi! Danke für die Infos!
Drei kleine Fragen noch dazu:
Ich persönlich würde "const string&" zurückgeben.
Das heißt also, dass es hier keinen einheitlichen Stil gibt, richtig?
Ich persönlich würde "const string&" zurückgeben. Das kann man direkt verwenden, ohne daß eine Kopie angelegt wird, man kann aber auch durch Zuweisung eine Kopie anlegen, wenn gewünscht.
Das bedeutet, der Anwender meiner Klasse bekommt eine direkte Referenzauf meinen Member, kann diesen aber nicht verändern? Wenn ich nun auf diese Weise ein Objekt zurückgebe, welches selber wiederum manipulierende Methoden (nicht const, etwa Setter) besitzt, können diese dann vom Benutzer meiner Klasse aufgerufen werden?
C++ hat im Gegensatz zu Java keine eigenen Objekttypen.
Äh, mit dem Wort Objekttyp meinte ich „Klasse“. Was ist denn dann ein Objekttyp? :o
Bin immer wieder begeistert von diesem Forum...
sommerfee
04-08-2010, 21:18
Das bedeutet, der Anwender meiner Klasse bekommt eine direkte Referenzauf meinen Member, kann diesen aber nicht verändern? Wenn ich nun auf diese Weise ein Objekt zurückgebe, welches selber wiederum manipulierende Methoden (nicht const, etwa Setter) besitzt, können diese dann vom Benutzer meiner Klasse aufgerufen werden?
Nein, es können dann nur diejenigen Methoden aufgerufen werden, die als "const" gekennzeichnet sind, ansonsten gibt es einen Compilerfehler.
Äh, mit dem Wort Objekttyp meinte ich „Klasse“.
So hatte ich es auch interpretiert. C++ hat keine eingebauten Funktionen und keine eingebauten Klassen. Man muß bei C++ unterscheiden zwischen der Sprache und der Standard-Laufzeitbibliothek, die z.B. std::string bereitstellt. Entwickelt man z.B. Kernel-Gerätetreiber für Windows in C++, stehen stattdessen andere (von MS bereitgestellte) Laufzeitbibliotheken zur Verfügung. Für Qt-Applikationen könnte man zwar std::string nehmen, nimmt aber in der Regel QString stattdessen, bei MFC-Anwendungen CString usw.
Bei Java ist das ja ein wenig anders, es gibt dort auch "eingebaute" Klassen wie Object, Int, String etc.
Liebe Grüße,
Axel
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.