Pointer values in Klassen
-
Hi,
ich hab noch eine kleine Frage an euch

Ich stell mir gerade die Frage wann es sinnvol ist ein Klassenattribut als pointer zu deklarieren oder normal zu deklarieren d.h. ohne Pointer.
zum Verständnis:
class MyClass { private: int *myIntPrt; int myInt; }was macht den Unterschied bzw. in welchem Fall brauch ich was?
Ok den Pointer sollte ich im Destruktor wieder löschen. Aber warum verwende ich überhaupt Pointer in Klassen?Ich hoffe ihr könnt mir hier mit euerer Erfahrung weiter helfen.
mfg byte
-
ByteRix schrieb:
Hi,
ich hab noch eine kleine Frage an euch

Ich stell mir gerade die Frage wann es sinnvol ist ein Klassenattribut als pointer zu deklarieren oder normal zu deklarieren d.h. ohne Pointer.
ich bin mal so frei und zitiere Artchis Blog:
Artchi schrieb:
Viele Benutzen in C++ Pointer obwohl dieses meistens nicht nötig ist. Das fällt mir sehr oft in Libraries und in Foren auf, wenn dort C++ Programmierer ihre Codeschnippsel zeigen. In C++ gibt es insgesamt drei verschiedene Variablen-Typen:
1. Objektinstanzen
2. Referenzvariablen
3. PointervariablenInteressant sind hier die Referenzen. In C++ ist eine Referenz kurz erklärt "ein anderer Name für ein Objekt". Weiterhin kann diese niemals NULL sein. Referenzen wurden damals in C++ eingeführt, weil Pointer in C mehr können und zulassen als eigentlich in den meisten Fällen benötigt wird.
Hier mal ein Beispiel, wie man Referenzen in einem Funktionskopf definiert:
void foo(string &str);
Der Aufrufer muß der Funktion ein gültiges string-Objekt übergeben. Ein NULL-Pointer ist direkt nicht möglich.
Weiterhin bewahrt man sich selbst als Implementierer dieser Funktion davor mit Pointern zu hantieren. Natürlich kann man sich zu dieser Referenz nachträglich einen Pointer besorgen. Hier bleibt einem als C++ Programmierer (zum Glück) weiterhin die Freiheit selbst zu entscheiden, was man mit seinem Code macht. Aber man muß es selbst explizit tun! Das ist der Unterschied, ob man von vornherein ausschliesslich mit Pointern arbeitet, obwohl es in dem Moment keinen Sinn macht. Oder die sichereren Referenzen verwendet.Wie kann ich eine Member-Reference in meiner Klasse anlegen? Ein Beispiel:
class Planet { private: SonnenSystem &sonnen_system; // Referenz auf Sonnensystem public: Planet(SonnenSystem &s) : sonnen_system(s) { } Planet(SonnenSystem &s) { sonnen_system = s; // Error! Zu spät initialisiert. } };Wie gehabt benutzen wir den &-Operator für unsere Variable, um zu zeigen, das es sich um eine Referenz handelt. Da aber diese Membervariable nicht NULL sein darf, muß diese vor der Objektkonstruktion (von Planet) initialisiert werden. Dazu benutzen wir die Initialisierer-Liste im Konstruktorkopf (zu erkennen an dem vorangestellten Doppelpunkt im ersten Konstruktor). Der Parameter s wird der Member-Reference sonnen_system übergeben - bevor das Planeten-Objekt konstruiert wird. Damit ist der Compiler zufrieden und meldet keinen Fehler.
Man sieht also, C++ hat sehr wohl sichere Techniken und das schon seit vielen Jahren. Nur nutzen tun sie leider die wenigsten Programmierer.
Pointer als Member-Variablen würden in dem obigen Beispiel dann Sinn machen, wenn das sonnen_system NULL sein könnte, d.h. es kein SonnenSystem zu dem Planet geben kann. Aber auch hier würde es Alternativen geben, z.B. Smartpointer aus boost bzw. aus dem kommenden ISO-C++ Standard.Ok den Pointer sollte ich im Destruktor wieder löschen.
Nur wenn du dem Pointer mal dynamischen Speicher zugewiesen hast, ansonsten nicht.
MfG
GPC
-
also besteht also "fast" nie die Notwendigkeit membervariablen als pointer zu deklarieren.
danke

mfg byte
-
Es gibt schon Gründe, die dafür sprechen - z.B. könnte hinter deinem myIntPtr ein ganzes int-Array stehen, das du zur Laufzeit noch vergrößern und anpassen willst (Stichwort Containerklasse), oder du willst den Pointer während der Laufzeit umbiegen (Referenzen können das nicht).
-
ByteRix schrieb:
also besteht also "fast" nie die Notwendigkeit membervariablen als pointer zu deklarieren.
danke

mfg byte
Ein Pointer (ebenso wie eine Referenz) ist einfach was Anderes: Es ist nur die "Verknüpfung"/"Assoziation"/"Link"/"Alias" auf das eigentliche Objekt.
Kennt man z.B: von "Desktopverknüpfungen" unter Windows oder "Links" unter Unixen.Wo Du das brauchst, brauchst Du es eben.

Es wird schnell auf "selbstverwaltete Heap-Objekte" verkürzt (die man z.B. im Konstruktor selbst anlegt und im Destruktor selbst löscht) .... aber es gibt viele andere Anwendungsfälle. Wenn z.B. mehrere Objekte auf dieselben Daten zugreifen sollen, braucht man so etwas.class Automobil { public: std::string standort; }; class Autobesitzer { std::string* woStehtMeinAuto; public: Autobesitzer(std::string const * standortAuto) : woStehtMeinAuto(standortAuto) {} void vergißAutoStandort() { woStehtMeinAuto = 0; } }; int main(voi) { Automobil car; car.standort = "Schloßparkplatz"; Autobesitzer ich(&car.standort); car.standort = "Theaterparkhaus" // ich weiß immer noch, wo mein Auto steht ... }Gruß,
Simon2.
-
Simon: mit den Strings ist das leider ein schlechtes Beispiel, da ein Pointer auf einen String nicht wirklich Sinn macht (intern verwendet string ja selbst einen Pointer), d.h. hier würde ein "string woStehtMeinAuto" ausreichen.
-
Th schrieb:
Simon: mit den Strings ist das leider ein schlechtes Beispiel, da ein Pointer auf einen String nicht wirklich Sinn macht (intern verwendet string ja selbst einen Pointer), d.h. hier würde ein "string woStehtMeinAuto" ausreichen.
Sehe ich nicht so. Im Gegenteil:
A) Es ist ja vollkommen egal, wie ein Objekt sich intern organisiert.
Mit der Kopie ("string ...") legt string eine "tiefe Kopie" an. Damit zeigt die Kopie auch auf einen anderen Speicherbereich als das Original.
Und das ist auch gut so !! Sonst wäre es keine Kopie.Das, was es sein soll, geht nur mit Zeiger (ggf. auch mit Referenz - aber auf keinen Fall mit Kopie) !
Nicht zu vergessen: Es wäre sogar höchst gefährlich, wenn mit Deinem Konstrukt der interne char-pointer des einen Strings in den anderen kopiert würde, weil string ein dynamischer Container ist, der sich ggf. anderen Speicher besorgt (z.B. wenn der neue Inhalt nicht mehr in den Speicherplatz des alten passt) und den alten freigibt.
Damit würde die Kopie (die davon ja gar nichts mitbekommen kann) aber auf einen ungültigen Speicherplatz verweisen, ohne die Chance zu haben, das mitzubekommen ....Gruß,
Simon2.
-
Simon, dann würden ja bei dir folgende 2 Strings unterschiedliche Standorte darstellen:
Automobil car; car.standort = "Schloßparkplatz"; Automobil car2; car2.standort = "Schloßparkplatz"; // --> &car.standort != &car2.standortDeswegen würde ich hier keine Pointer einsetzen, sondern einen simplen String-Vergleich -)
Aber für andere Beispiele gibt es sinnvolle Verwendungen von Pointern!
-
Th schrieb:
Simon, dann würden ja bei dir folgende 2 Strings unterschiedliche Standorte darstellen:
...Wieso das denn ?
Wenn ich Objekte vergleiche, benutze ich natürlich den klassenangemessenen Vergleichsoperator ... und nicht die Speicherposition.Wie machst Du das denn sonst mit den Stringvergleichen ?
Gruß,
Simon2.
-
Kann man sagen, dass man in C++ Zeiger nur noch für Polymorphie und dynamische Speicherverwaltung braucht und für alles andere Referenzen nehmen kann?
-
1310-Logik schrieb:
Kann man sagen, dass man in C++ Zeiger nur noch für Polymorphie und dynamische Speicherverwaltung braucht und für alles andere Referenzen nehmen kann?
Hi,
also ich merke mir immer: Wenn ein Verweis optional (= "kann 0 sein") oder variabel (= "kann zur Lebenszeit auf unterschiedliche Objekte verweisen") ist, verwende ich einen Pointer.
Sonst eine Referenz.
(und bei der Heap-Speicher-Verwaltung kann man nur optionale&variable Verweise verwenden => Pointer)Gruß,
Simon2.