Wie "this" bei Konstruktor-Aufruf angeben?

Hey,

ich stehe vor einem kleinen Problem:

Ich hab Klasse A und Klasse B.

Klasse A soll eine Instanz von Klasse B anlegen, und B sich selbst übergeben, so dass B auch Funktionen aus A aufrufen kann:

A.h

class A {
.
.
.
private:
   B* _b;
.
.
.
}

irgendwo in A.cpp:

_b = B(this);

Im B.h steht folgendes:

class B {

public:
   B(A* a);
.
.
.
}

Beim compilieren bekomme ich folgenden Fehler:

cannot convert 'B' to 'B*' in assignment

    _b = B(this);
       ^

Scheint so als ob das mit dem Konstruktor-Aufruf klappt, er aber die B-Instanz nicht in _b ablegen kann?!
Ich komm nicht weiter. Hat jemand nen Plan woran's liegt und kann mir einen Tipp geben?

Es geht nicht um die Übergabe von this.

Du hast in A B* _b;

also ist _b ein B* und kein B. Du meinst evtl.

B tmpB(this);
_b = &tmpB;

Leider wird der Wert von _b ungültig sobald der c'tor zu Ende ist.

Aber dir zu helfen zu wollen führt vermutlich eher in die falsche Richtung... was soll der Sinn sein ?

Nachtrag:
Damit eine Klasse "Methoden einer anderen Klasse ausführen kann", braucht es solche Zirkel nicht.
Riecht eher nach Vererbung

Das B sollte mit new erzeugt werden. Etwa so:
_b = new B(this);
Ohne Gewehr, mein C++ ist ziemlich angerostet.

DrDiettrich:
Das B sollte mit new erzeugt werden. Etwa so:
_b = new B(this);
Ohne Gewehr, mein C++ ist ziemlich angerostet.

Auch wenn du für größere Systeme vermutlich Wahr hast, gilt das dennoch nicht für Arduinos.

New ist da überhaupt nicht nötig. Man kann Objekte in anderen Objekten auch bequem statisch anlegen. Man muss sich nur abgewöhnen zu versuchen Konstruktoren direkt aufzurufen. Das geschieht automatisch! Und um Objekte zu initialisieren eine Initialisierungsliste verwenden, statt irgendwas im Konstruktor-Körper zu tun.

Aber wie gesagt mal darüber nachdenken ob das eine "has-a" oder "is-a" Beziehung sein soll.

Kann man statisch machen, dann muß der Code eben an anderen Stellen geändert werden :-]

Danke für die vielen Antworten. Hilft mir aber irgendwie überhaupt nicht weiter. Liegt vielleicht daran, dass ich aus der sehr objektorientierten Java-Welt komme, und es da nonsense ist für sowas das ganze statisch zu bauen.

Hintergrund der ganzen Misere:

Klasse A ist meine zentrale Einstiegsklasse in eine Library.

Im Sketch instantiiert man A und nutzt dann A entsprechend.
Ein Teil der Funktionalität (ein besonderes Feature der Library) ist aber in B ausgelagert.
Also legt sich A eine Instanz von B an und nutzt diese dann auch.

In der Java-Welt würde man B nun eine Rückreferenz auf A geben, so dass B auch Methoden aus A nutzen kann.

Und genau daran scheitert es gerade.
Dass es statisch geht leuchtet ein. Aber das ist für mich kein sauberer Aufbau.

Vererbung könnte hier funktionieren. Ist aber irgendwie nicht passend: Weder kann man B alleine nutzen, noch ist A ein erweitertes B.

@michael_x hat es offenbar am exaktesten getroffen. Da es wohl nicht an der Übergabe von "this" hapert, kann man das Problem auf "wie erzeuge ich in A eine Instanz von B und lege diese in einer Klassenvariable von B ab, so dass ich sie später noch nutzen kann" reduzieren.

Gruß
Alex

Referenzen schreibt man in C++ mit &.
B& b;

Auf einem Arduino sollte man auf dynamische Speicherverwaltung weitestgehend verzichten, es wird sogar gemunkelt, daß die noch fehlerhaft ist. Java mogelt da auch, mit der Garbage-Collection. Deshalb die Empfehlung, die Instanzen statisch zu erzeugen, und dann in setup() zu initialisieren, soweit das im Konstruktor nicht möglich ist. In Deinem Fall wäre das dann
a.init(b);
wobei a zu diesem Zeitupunkt auch b initialisieren kann.

Dass es statisch geht leuchtet ein. Aber das ist für mich kein sauberer Aufbau.

Das Problem ist das "für mich".
Bei Controllern mit sehr begrenztem RAM und der Aufgabe, ewig zu laufen, ist eine Verwendung von new für mich kein sauberer Aufbau. :wink:

Wenn es von A und B jeweils nur 1 Instanz gibt und geben kann, wärst du mit statischen Methoden besser dran. In c++ braucht man übrigens (anders als in java) gar keine Klassen zu erfinden, wenn es keinen Sinn macht. Wird hier bei arduinos allerdings gerne anstelle von namespace so gemacht.

Die "Arduino-Sprache" ist c++, das ein bisschen aussehen soll wie java (z.B. Datentyp boolean).
Wo das eher stört, kann man es auch sein lassen.

Das Problem ist das "für mich".

Das mag durchaus sein.

Bei Controllern mit sehr begrenztem RAM und der Aufgabe, ewig zu laufen, ist eine Verwendung von new für mich kein sauberer Aufbau.

Dass das C++ "new" hier gar nicht funktioniert, wurde ja schon geschrieben.

Ob ich jetzt zwei Libs benutze und da jeweils eine Instanz ins leben rufe, oder eine Lib und darin dann zwei Objekt-Instanzen, ist doch völlig schnuppe, oder?

Wenn es von A und B jeweils nur 1 Instanz gibt und geben kann, wärst du mit statischen Methoden besser dran.

Dem ist aber nicht unbedingt so. In den meisten Fällen reicht im Sketch eine Instanz von A. Aber es gibt Ausnahmefälle, da wird man zwei Instanzen brauchen. Und dann braucht jede A-Instanz sein eigenes B.

Mein momentaner Workaround wäre, alles aus B einfach in A zu stecken. Aber aufgrund der Größe von A und B wird das schnell unübersichtlich und schlecht wartbar. Und das versuche ich zu vermeiden.

In c++ braucht man übrigens (anders als in java) gar keine Klassen zu erfinden, wenn es keinen Sinn macht.

Das soll jetzt echt kein herablassender Kommentar sein: Aber in egal welcher Sprache: Wenn eine Klasse keinen Sinn macht, dann sollte man sie nicht erfinden/erstellen.

In meinem Fall ergibt die Klasse B aber Sinn.

Die ganzen bekehrungsversuche in ehren: Es muss doch möglich sein dass A sich eine Instanz von B anlegt und diese in einer Klassenvariable speichert, so dass man im späteren Verlauf von A noch darauf zugreifen kann.

Irgendwie klingt das total banal und kann eigentlich nicht sooo kompliziert sein, aber ich steh dermaßen auf dem Schlauch, dass ich den Wald vor lauter Bäumen nicht sehe. Wäre nett wenn da jemand - trotz der vllt. skurril anmutenden verhältnisse - etwas unterstützung leisten könnte.

Viele Grüße
Alex

Wie machst Du sowas denn in Java? In C++ würde ich versuchen
B _b;
in A einzubauen.

Problem gelöst:

A.h

class A {
B *_b;
...
}

A.cpp

// irgendwo im Konstruktor von A
_b = new B(this);

Ich hab nur die Klassenvariable "_b" im Header aus dem "private:" Bereich in den allgemeinen Bereich (noch vor "public:") verschoben. Hoffentlich heisst das jetzt nicht gleich dass die Variable statisch ist?! Dazu bin ich in C++ nicht fit genug. Mal schauen/ausprobieren.

Bzgl. "new" Operator: c++ - Operator new for Arduino - Stack Overflow

Hat keiner gesagt, dassnewnicht geht. Ich halte es nur für generell nicht optimal / sauber.
In c++ bräuchte (anders als in java) eigentlich jedes new ein delete.
Aber wenn das nur in setup oder gar vorher passiert, ok.

aus dem "private:" Bereich in den allgemeinen Bereich (noch vor "public:") verschoben

Das ist dasselbe... alles vor public: ist private:

Wenn du in einer Klasse ein Objekt einer anderen Klasse deklarierst wird das automatisch erzeugt. Fertig. Es ist das gleiche wie bei Variablen. Da muss man sonst nichts tun. Konstruktoren werden automatisch aufgerufen wenn das Objekt instantiiert wird! Wenn dann nur Default Konstruktoren vorhanden sind muss man sonst nichts tun.

Was du unbedingt verinnerlichten musst, ist dass diese Variablen schon erzeugt wurden wenn du im Konstruktor bist. Also braucht man einen Mechanismus dafür wenn man bei der Instantiierung Werte übergeben muss. Das ist die Initialisierungsliste (das solltest du dringend nachschlagen wenn du was mit OOP in C++ machst).
Eine Falle mit this ist dabei, dass zu dem Zeitpunkt das eigene Objekt noch nicht vollständig erzeugt wurde. Man kann also über this auf ungültige Daten zugreifen. Wenn man nur einen Zeiger zuweist ist es aber in Ordnung.

Das größere Problem bei dieser Sache ist die gegenseitige Abhängigkeit der Klassen. Das kann man auch schnell reinfallen.