Freundfunktionen && zirkuläre Abhängigkeiten

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Freundfunktionen && zirkuläre Abhängigkeiten

Beitrag von kaiserludi »

Moin.

Ich habe eine Klasse Bar, die Membervariablen einer Klasse Foo hält. Vereinfacht sieht das so aus:

Code: Alles auswählen

class Bar
{
	Foo mFoo;
};
Es handelt sich dabei ausdrücklich um ein Foo, nicht etwa eine Foo& oder einen Foo*.
Entsprechend muss Bar.h Foo .h inkludieren und kann nicht einfach Foo via class Foo; vorraus deklarieren.

Nun benötigt aber eine Funktion aus Bar friend Zugriff auf Foo, während ich ungern auch dem ganze Rest von bar friend Zugriff auf Foo geben möchte.
Dummerweise muss nun aber Foo.h natürlich Bar.h inkludieren, damit ich eine Memberfunktion von Bar als Friend in Foo Angeben kann, einfach nur class Bar; eicht nur, wenn ich die ganze Klasse als friend angeben will, nicht bei einzelnen Funktionen.

Wie löse ich diese zirkulare Abhängigkeit nun ab besten auf?

Die beste Lösung, auf die ich bisher gekommen bin, ist dieser Pattern (Wenn das wirklich die beste Lösung ist, dann ist darauf bestimmt schon wer vor mir gekommen. Kann mir wer sagen, obs für den pattern einen konkreten Namen gibt?):

Code: Alles auswählen

class Foo;
class Bar;

class FooBar
{
	static void friendOfFoo(void);
	friend class Foo;
	friend class Bar;
};

class Foo
{
	friend void FooBar::friendOfFoo(void);
};

class Bar
{
	friend void FooBar::friendOfFoo(void);
	void friendOfFoo(void);
	Foo mFoo;
};
Damit schwirrt mir nun aber eine extra Klasse da rum, die nichts anderem dient, als Unzulänglichkeiten der Sprache auszugleichen.
Bei so etwas fundamentalem und primitiven muss es doch auch einfacher gehen?
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
TGGC
Establishment
Beiträge: 569
Registriert: 15.05.2009, 18:14
Benutzertext: Ich _bin_ es.
Alter Benutzername: TGGC
Echter Name: Ich _bin_ es.
Wohnort: Mainz
Kontaktdaten:

Re: Freundfunktionen && zirkuläre Abhängigkeiten

Beitrag von TGGC »

http://stackoverflow.com/questions/6310 ... -as-friend

Aber: Muss es wirklich eine friend Methode geben? Und musst du wirklich einen Datamember statt einer Referenz/Pointer machen? Solche physikalischen Abhaengigkeiten sind meist nicht so toll.
Benutzeravatar
Artificial Mind
Establishment
Beiträge: 802
Registriert: 17.12.2007, 17:51
Wohnort: Aachen

Re: Freundfunktionen && zirkuläre Abhängigkeiten

Beitrag von Artificial Mind »

Ich weiß, das ist jetzt nicht besonders hilfreich, aber trotzdem:
Wenn du nur der einen Funktion friend access gewähren willst, dem Rest von Foo aber nicht, ist es dann nicht eh sinnvoller, diese Funktion als freie/externe Funktion zu machen und nicht innerhalb von Foo?
Mir fällt nämlich kein guter Grund ein, nur der einen Memberfunktion den Zugriff zu geben, aber nicht der ganzen Klasse.
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Freundfunktionen && zirkuläre Abhängigkeiten

Beitrag von kaiserludi »

TGGC hat geschrieben:http://stackoverflow.com/questions/6310 ... -as-friend

Aber: Muss es wirklich eine friend Methode geben? Und musst du wirklich einen Datamember statt einer Referenz/Pointer machen? Solche physikalischen Abhaengigkeiten sind meist nicht so toll.
Die Friend Funktion ist eine Factory Method. Nur Bar soll neue Foos erstellen können (copy construction aus bestehenden Foo-Instanzen hingegen ist public), weswegen der Foo-Konsturktor private ist. Gleichzeitig braucht aber Bar keinen weiteren Zugriff Implementierungsdetails von Foo. Deswegen möchte ich nur der Factory Method und nicht auch dem Rest von Bar Friend-Zugriff auf Foo geben.
Bar hält einen Vector<Foo>. Der Grund dafür, dass es kein Vector<Foo&> oder Vector<Foo*> ist, ist, dass ich so die Foos ohne dynamische Allokation erstellen kann.

EDIT: Zu deinem Link: Ja, das würde auch funktionieren, aber dann kann ich ja auch gleich so vorgehen, wie im FooBar Beispielcode aus dem OP oder wo ist der Vorteil, wnen ich einen FooPrivateAccessKey habe? FooBar könnte ich FooFactory nennen, dann wäre das eigentlic hauch ziemlich klar.
Ich habe mich eher gefragt, obs nicht irgendwie möglich ist, ohne eine zusätzliche Klasse auszukommen, aber scheint wohl nicht der Fall zu sein.
Artificial Mind hat geschrieben: Mir fällt nämlich kein guter Grund ein, nur der einen Memberfunktion den Zugriff zu geben, aber nicht der ganzen Klasse.
Der Grund ist, dass so nur diese Klasse auf ihre private Memberfunktion zugreifen kann. Auf eine freie Funktion hätte dann wieder jeder Zugriff.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
TGGC
Establishment
Beiträge: 569
Registriert: 15.05.2009, 18:14
Benutzertext: Ich _bin_ es.
Alter Benutzername: TGGC
Echter Name: Ich _bin_ es.
Wohnort: Mainz
Kontaktdaten:

Re: Freundfunktionen && zirkuläre Abhängigkeiten

Beitrag von TGGC »

kaiserludi hat geschrieben:Bar hält einen Vector<Foo>. Der Grund dafür, dass es kein Vector<Foo&> oder Vector<Foo*> ist, ist, dass ich so die Foos ohne dynamische Allokation erstellen kann.
Klar werden auch in einem Vector<Foo> der Speicher der Elemente dynamisch angelegt, zumindest einmal und dann immer wenn die Kapazitaet des vectors nicht mehr fuer den Inhalt reicht. Dann wird der Speicher aller bisherigen Elemente sogar nochmal komplett umkopiert. Wenns trotzdem so sein muss, benutze doch einfach einen std::vector<Foo>*. Damit bezahlst du nur eine zusaetzliche Allokation bei der Konstruktion von Bla + 4 Byte mehr Speicherverbrauch fuer die physikalische Entkopplung.

Eine andere Frage ist, warum dies Factoryfunktionalitaet ueberhaupt in Bar ist und nicht in Foo, denn so ist Foo ja nie mehr allein nutzbar.
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Freundfunktionen && zirkuläre Abhängigkeiten

Beitrag von kaiserludi »

Das der Vektor intern doch wieder dynamisch allokiert, ist mir bewusst. Ich wollte bloß weitere zusätzliche dynamische Allokationen vermeiden. Bei nur einer zusätzlichen pro Bar wäre das aber schon weniger wild.

Die Factoryfunktionalität kann leider nicht in Foo sein, weil der ganze Sinn hinter der Fabrikmethode ist, dass man sowohl von Foo als auch von Bar erben und dann einfach die Fabrikmethode dahingehend überschreiben kann, keine Foos, sondern Instanzen von von Foo erbenden Klassen zu erzeugen. Wäre die Funktion nun in Foo, dann könnte man sie entweder erst nach der Konstruktion der Instanz aufrufen, dessen Klasse man über die Funktion bestimmen will, was entsprechend natürlich zu spät wäre, oder man könnte, wenn die Funktion static macht, die nicht mehr in erbenden Klassen überschreiben.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
TGGC
Establishment
Beiträge: 569
Registriert: 15.05.2009, 18:14
Benutzertext: Ich _bin_ es.
Alter Benutzername: TGGC
Echter Name: Ich _bin_ es.
Wohnort: Mainz
Kontaktdaten:

Re: Freundfunktionen && zirkuläre Abhängigkeiten

Beitrag von TGGC »

kaiserludi hat geschrieben:Ich wollte bloß weitere zusätzliche dynamische Allokationen vermeiden. Bei nur einer zusätzlichen pro Bar wäre das aber schon weniger wild.
Wenn du Speicherprobleme hast, das du schon auf jede Allokation schauen musst, dann solltest du ehh einen globalen Pool von Foo haben, die sich alle Bar-Instanzen teilen.
Benutzeravatar
Blue Cobold
Beiträge: 58
Registriert: 13.06.2001, 00:00
Kontaktdaten:

Re: Freundfunktionen && zirkuläre Abhängigkeiten

Beitrag von Blue Cobold »

Ich denke hier sollte man wieder die generelle Frage nach dem: "Was soll da überhaupt gebaut werden?" gestellt werden. Denn bisher klingen die Ideen und Anforderungen eher gruselig. Friend-Factories, zyklische Abhängigkeiten und was nicht alles.
Da ist doch eher ein arges Fehldesign im Gange. Mit einer Beschreibung dessen, was hier überhaupt modelliert werden soll, ließe sich sicher eine deutlich bessere und vor allem auch saubere Lösung finden.
Benutzeravatar
Artificial Mind
Establishment
Beiträge: 802
Registriert: 17.12.2007, 17:51
Wohnort: Aachen

Re: Freundfunktionen && zirkuläre Abhängigkeiten

Beitrag von Artificial Mind »

Ich finde das klingt ein wenig nach Abstract Factory Pattern.
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: Freundfunktionen && zirkuläre Abhängigkeiten

Beitrag von kimmi »

Wobei die AbstractFactory aber eine eigene Klasse spendiert werden sollte. Ansonsten fängt man sich nämlich all diesen Ärger mit den zyklischen Anhängigkeiten und dem daraus resultierenden Ärger ein.

Gruß Kimmi
Antworten