Pointer Fragen

Tach

Ich habe zwei Fragen bezüglich C++ Pointern:

  1. Nehmen wir an ich habe ein Objekt einer Hauptklasse (nennen wir die mal „Boss“) und in diesem Boss Objekt existieren viele Objekte einer anderen Klasse („Slave“). Jedes mal wenn ich von Slave eine spezielle Funktion aufrufe, muss diese möglicherweise eine Funktion des eigenen Boss aufrufen (zB um Daten zu besorgen).
    Die Frage: Gibt es eine einfache Möglichkeit diese Funktion von Boss aufzurufen, ohne in jedem Slave Objekt den Pointer auf Boss zu speichern.

  2. Gibt es schnelle Möglichkeit für ein Objekt den Pointer von sich selbst zu besorgen („return self“ oder sowas)?

Danke für Antworten

Hallo,

  1. Gibt es schnelle Möglichkeit für ein Objekt den Pointer von
    sich selbst zu besorgen („return self“ oder sowas)?

dieser Pointer heißt „this“ in C++.

Andreas

  1. Nehmen wir an ich habe ein Objekt einer Hauptklasse (nennen
    wir die mal „Boss“) und in diesem Boss Objekt existieren viele
    Objekte einer anderen Klasse („Slave“). Jedes mal wenn ich von
    Slave eine spezielle Funktion aufrufe, muss diese
    möglicherweise eine Funktion des eigenen Boss aufrufen (zB um
    Daten zu besorgen).
    Die Frage: Gibt es eine einfache Möglichkeit diese Funktion
    von Boss aufzurufen, ohne in jedem Slave Objekt den Pointer
    auf Boss zu speichern.

Je nachdem, wie deine Software aufgebaut ist - vielleicht. Wenn es überhaupt und insgesamt nur einen Boss gibt (und sich das in Zukunft auch keinesfalls ändert), könnte man einen Zeiger auf ihn als oder als statisches Feld seiner eigenen oder der Sklavenklasse, bzw. in irgendeiner Ausprägung des sogenannten „Singleton“-Pattern aufbewahren (googlebar). Man könnte auch an der Stelle, wo der Sklave Informationen seines Bosses benötigt, den Boss oder die benötigte Information als Parameter einfach hineinreichen. Ansonsten muss man wohl in den sauren Apfel beissen und sich den Boss pro Sklave irgendwie merken.

Viele Grüße,
Sebastian

Kann ich den auch per return direkt übergeben?

Kann ich den auch per return direkt übergeben?

Klar.

Hi Apo,

Kann ich den auch per return direkt übergeben?

return this;
oder z.B auch:
return \*this;

sind legale Statements.

Wichtig! Die Lebensdauer des referenzierten Objektes wird in C++ nicht dadurch verlängert, dass du den Wert, den du per Return zurückgegeben hast, in einer Variablen speicherst (dies ist ein wesentlicher Unterschied zu Java).

struct A
{
 A\* ptr() { return this; }
 virtual void process() { ... }
};

int main()
{
 A\* pX = new A;
 A\* pMyPointer = pX-\>ptr();

 delete pX;


 // pMyPointer is invalide ab hier !!
 // und somit auch der folgende Aufruf
 /\* HERE \*/

 pMyPointer-\>process(); 
}

Das mag auf den ersten Blick noch mit deinem Compiler funktionieren, aber dann solltest du mal ein new char[128]; direkt hinter dem /* HERE */ einfügen …

Gruss
norsemanna

Wenn das Boss Objekt den ganzen Programmdurchlauf lang existiert, könnte ich es doch auch einfach in der Main definieren (oder gleich global) und dann von überall aus darauf zugreifen. Oder ist das ein schlechter Programmierstil?

Nebenfrage: Was wenn ich durch Threads an einen Vektor in diesem einen Boss Objekt gleichzeitig versuche Elemente anzuhängen, könnte es dann zu Fehlern kommen?

mfg
Apoth

Hallo Apoth,

Wenn das Boss Objekt den ganzen Programmdurchlauf lang
existiert, könnte ich es doch auch einfach in der Main
definieren (oder gleich global) und dann von überall aus
darauf zugreifen. Oder ist das ein schlechter Programmierstil?

Sinn der OO ist es eigentlich, dass man das System auch erweitern kann.

Wenn du jetzt Sklavenhandel einführst, gibt es mehrere Bosse, evtl. sogar noch Sklavenhändler-Objekte, welche man vom Boss ableiten kann.

Direkter Zugriff ist schlechter Stil, weil du dann auch das Sklaven-Objekt umschreiben musst.

MfG Peter(TOO)

Das Programm befindet sich noch im Design Stadium, ich müsste also nix umschreiben
Außerdem gibts definitiv nur einen Boss.
Würde der Programmierstil in dem Fall passen?

Hossa :smile:

  1. Nehmen wir an ich habe ein Objekt einer Hauptklasse (nennen
    wir die mal „Boss“) und in diesem Boss Objekt existieren viele
    Objekte einer anderen Klasse („Slave“).

Die Frage: Gibt es eine einfache Möglichkeit diese Funktion
von Boss aufzurufen, ohne in jedem Slave Objekt den Pointer
auf Boss zu speichern.

Nein, die Slave-Objekte wissen ja nicht, dass sie Member von Boss sind.

Da du aber definitiv nur einen einzigen Boss hast, kannst du das auch im Programm so implementieren und dein Problem elegant lösen. Dazu machst du alle Konstruktoren von Boss private. Das verhindert die Erzeugung von Boss-Objekten. Zusätzlich deklarierst du eine statische Member-Funktion Ref() als public. Das sieht dann etwa so aus:

class Boss
{
 Slave a;
 Slave b;
 ...
private:
 Boss(); //Alle Konstruktoren "private" machen

public:
 static Boss& Ref()
 { static Boss b;
 return b;
 }
}

Eine statische Member-Funktion (wie hier Ref) hat keinen this-Zeiger. Das heißt für ihren Aufruf ist kein konkretes Boss-Objekt nötig, ihr Aufruf erfolgt unabhängig von allen Boss-Objekt durch:

Boss::Ref();

Da Ref() eine Member-Funktion von Boss ist, hat sie Zugriff auf alle privaten Objekte, insbesondere auf die privaten Konstruktoren. Innerhalb von Ref() wird ein statisches Boss-Objekt b einmalig erzeugt und eine Referenz auf dieses Boss-Objekt b zurück geliefert. Von nun an kann das Boss-Objekt überall im Quelltext durch

Boss::Ref()

angesprochen werden. insbesondere innerhalb der Slave-Klasse bzw. innerhalb deren Funktionen.

  1. Gibt es schnelle Möglichkeit für ein Objekt den Pointer von
    sich selbst zu besorgen („return self“ oder sowas)?

Das wurde unten schon beantwortet. Der Zeiger auf das aktuelle Objekt heißt „this“.

Viele Grüße

Die Methode klingt interessant. Hat die auch nen speziellen Namen. Klingt für mich änhlich wie das Singleton Schema das SebastianS erwähnt hat.

Wie benutze ich deinen Vorschlag dann?
Benutze ich den Pointer von Boss::Ref (bei dem nie das Objekt ersetzt wird) oder kann ich einfach überall Boss::do_something() schreiben?

mfg
Apoth

Hallo,
Jo das ist das Singleton-Pattern! Ist halt immer dann sinnvoll wenn du echt sicher bist das es nur ein Objekt geben darf.
Der Aufruf von Methoden passiert immer über die getBoss() oder halt hier die ref() Methode! Ich bin mir allerdings n bisschen unsicher wie das mit statischen variablen innerhalb von Funktionen aussieht. Ich kenne das so, das man eine statische private Member macht. In der getBoss wird dann abgefragt ob diese gleich Null ist, wenn ja dann mit new Objekt erzeugen und zuweisen.
Zusätzlich kann man dann noch eine delete Methode bauen die das Singleton zerstört. Da sollte man dann aber dolle drauf achten das man extern immer über Boss:ref() geht und keine weiteren Pointer zuweist da man ansonsten schnell mal nen Nullzeiger hat der undefiniertes Verhalten auslösen kann.

Hossa :smile:

Der Aufruf von Boss erfolgt bei dem genannten Schema immer über

Boss::Ref()

und du erhälst eine Referenz auf das einzig existierende Boss-Objekt zurück. Möchtest du z.B. auf das Objekt a innerhalb des Boss-Objektes zugreifen, schreibst du einfach:

Boss::Ref().a

Ich nutze diese Form recht gerne, weil ich durch „Boss::“ quasi einen Namespace habe.

Wenn dich das „Boss::“ stört, kannst du an Stelle der Ref()-Funktion auch eine friend-Funktion einbauen:

class Boss
{
 Slave a;
 Slave b;
 ...
private:
 Boss(); //Alle Konstruktoren "private" machen

 friend Boss& theBoss();
};

Boss& theBoss()
{ static Boss b;
 return b;
}

Die friend-Funktion theBoss() hat Zugriff aus alle privaten Elemente der Klasse Boss, also auch auf die privaten Konstruktoren. Daher klappt das genau so wie mit der vorigen Funktion Ref().

Auch hier gibt es genau ein Boss-Objekt, das du über den Aufruf theBoss() ansteuerst. Möchtest du also z.B. auf das Element a des Boss-Objektes zugreifen, schreibst du einach:

theBoss().a

Ob diese Konstruktion einen bestimmten Namen hat, weiß ich leider nicht. Sie wird gerne benutzt, um Resourcen anzusteuern, die nur einmal verfügbar sind, etwa für Drucker, Kartenleser, …

thePrinter();
theCardReader();

Die meisten Implementierungen machen jedoch den Fehler, dass sie einen Pointer zurück liefern. Um Ärger zu vermeiden, nimmt man am besten eine Referenz, die bezieht sich immer auf ein existierendes Objekt, so dass man sich nicht mit irgendwelchen Null-Zeigern rumschlagen muss.

Viele Grüße