2012-03-27 5 views
10

Ich habe gerade über friend class Konzept in C++ (Ich habe für ein bisschen gegoogelt, aber diese answer brachte mich zum Lachen, bis ich die wichtigsten Teile erinnerte), und ich versuche, es in das Projekt zu integrieren Daran arbeite ich gerade. Die kurze Frage wird am Ende ausgesondert, aber im Allgemeinen bin ich verwirrt durch vollständigen Mangel an Vorwärtsdeklarationen in meinem Arbeitscode.Wie wird die Deklaration für das Friend-Class-Konzept nicht benötigt?

Alle meine Klassen werden durch (Teil-) Ordner getrennt und jeder in einem separaten .h und CPP Datei, aber das sollte genug sein, ein Gefühl zu Abhängigkeiten erhalten:

// FE.h - no implementations - no .cpp file 
class FE 
{ 
    private: 
     virtual void somePrivateFunc() = 0; 
    // 90% virtual class, interface for further implementations 
    friend class TLS; 
}; 

// DummyFE.h 
#include "FE.h" 
class DummyFE :: public FE { 
    /* singleton dummy */ 
    private: 
     // constructor 
    public: 
     static DummyFE& instance(); 
}; 
// DummyFE.cpp 
#include "DummyFE.h" 
// all Dummy FE implementation 

// ImplFE.h 
#include "FE.h" 
class ImplFE :: public FE { /* implemented */ }; 
// ImplFE.cpp 
#include "FE.cpp" 
// all Impl FE implementations 


// SD.h - implements strategy design pattern 
//  (real project has more than just FE class in here) 
#include "FE.h" 
#include "DummyFE.h" 
class SD 
{ 
    private: 
     FE &localFE; 
    public: 
     SD(FE &paramFE = DummyFE::instance()); 
    // ... and all the other phun stuff ... 
    friend class TLS; 
}; 
// SD.cpp - implementations 
# include "SD.h" 
/* SD implemented */ 

// TLS.h - implements strategy design pattern 
      (on a higher level) 
#include SD.h 
class TLS{ 
    private: 
     SD *subStrategy; 
    public: 
     void someFunctionRequiringFriendliness(); 
} 

// TLS.cpp - implementations 
#include "TLS.h" 
void TLS::someFunctionRequiringFriendliness(){ 
    this->subStrategy->localFE.somePrivateFunc(); // ok! 
} 

Jetzt hatte ich Party all dies mit allen Abhängigkeiten tatsächlich zu kompilieren (musste es in ein Klassendiagramm am Ende schreiben, um es funktionieren zu lassen), aber jetzt tut es. Die Tatsache, dass ist eigentlich verwirrend mich, ist, dass keine Vorwärtsdeklarationen benötigt wurden. Ich weiß über Vorwärtsdeklarationen von früher, und nur für den Fall, ich habe mein Gedächtnis mit this answer aktualisiert.

Also, um zu versuchen und zu halten es klar, meine Frage: Wenn die class TLS als Freund erklärt, wie wurden keine expliziten vorwärts kommen Erklärungen benötigt? Bedeutet das, dass eine friend class Deklaration eine Forward-Deklaration ist? Für mich fehlt hier intuitiv etwas ... Und da es kompiliert und normal funktioniert, kann jemand helfen, meine Intuition zu korrigieren? : D

PS Entschuldigung für solch eine lange Einführung in die Frage und eine Reihe von Code. Bitte kommentieren Sie nicht mein Code-Konzept - Freunde sind hier gut, ich bin mir ziemlich sicher, dass es für mein aktuelles Projekt korrekt ist (es ist nur ein bisschen schwer von diesem Skelett zu sehen). Ich möchte nur wissen, warum nirgendwo eine Vorwärtsdeklaration benötigt wurde.

Antwort

6

Sie haben Recht, die Freundesdeklaration ist eine Art Vorwärtsdeklaration.

Folgende compiliert:

class A; 
class B 
{ 
    friend A; 
}; 

oder

class B 
{ 
    friend class A; 
}; 

dies nicht:

class B 
{ 
    friend A; 
}; 

Es ist nicht wirklich die friend Erklärung, dass class A voraus erklärt, aber die class ke yword. Deshalb funktioniert das zweite Beispiel nicht, weil es nicht weiß, was A ist. Wenn Sie zuvor wie im ersten Snippet A deklarieren, kann A in eine Klassendeklaration aufgelöst werden.

I stand corrected.

+0

Hm. Seltsam. Ich habe gerade die Situation, die Sie gesagt haben * kompiliert nicht in meiner Version des Codes (es spiegelt sich hier durch die Tatsache wider, dass FE TLS nicht weiterleitet, oder es überhaupt einschließt) - und es funktioniert! Das verwirrt mich! Ah, und ich habe gerade bemerkt, dass du die Syntax 'Freund A' anstelle von 'Freund Klasse A' benutzt hast. Könntest du das weiter ausführen, habe ich versehentlich die Forward- und Friend-Deklaration in eine zusammengefasst? – penelope

+1

Hinweis: Das erste Snippet wird in C++ 03 (für diejenigen, die C++ 11 noch nicht verwenden können) nicht kompiliert. Das zweite Snippet kompiliert nicht mit g ++ 4.5 oder clang ++ 3.0 (selbst im C++ 11-Modus). –

+0

@Luchian Ich bin verwirrt, wie Sie Ihr zweites Beispiel kompiliert haben? Dies veranlasste mich, diese Frage zu stellen, die darauf hinweist, dass Ihr zweites Beispiel nicht kompilieren sollte: http://stackoverflow.com/questions/14114956/friend-declaration-not-forward-declaring – JaredC

0

Heißt das, dass ein Freund Klassendeklaration ist eine zukunfts Erklärung alle in ihm selbst?

Ja

7
friend class TLS; 

Diese Syntax ist eine Erklärung in sich selbst, das ist, warum Sie nicht eine zusätzliche vorherige Erklärung des Typs benötigen. Beachten Sie, dass die Deklaration friend (speziell für Funktionen) etwas anders ist als eine Deklaration im umschließenden Namespace.

Insbesondere, außer es gibt auch eine Deklaration im umschließenden Namespace, kann eine in einer friend Deklaration deklarierte Funktion nur durch argumentabhängige Suche gefunden werden (und kann nicht außerhalb der Klasse definiert werden). Das gleiche gilt für Klassen, es sei denn, es gibt auch eine Deklaration auf Namespace-Ebene. Der so deklarierte Typ ist außerhalb der Klasse, die ihn als Freund deklariert, nicht verfügbar.

class B { 
    friend class A; 
}; 
//A foo(); // Error: A is not declared here! 
class A; 
A foo();  // Fine 
+0

Ich habe mich gefragt, warum ich 'TLS' in' FE' und 'SD' nicht explizit deklarieren muss, aber das ist eine Menge neuer Informationen. Was Sie vorgeschlagen haben (das Deklarieren von Typen * nur * im Körper einer anderen Klasse), würde wahrscheinlich verwendet werden, um die internen Funktionen der Klasse zu implementieren oder ähnliches? – penelope

+0

@penelope: Ich denke, es ist nur ein Nebeneffekt, wie Lookup durchgeführt wird. Ich habe nicht viel über Typen nachgedacht, wo es zu sein scheint * es gibt einen Typ A, der Zugriff auf diese Klasse hat * und nichts anderes (dh Sie können 'A' nicht als richtigen Typ selbst innerhalb von' B' verwenden). Aber im Fall von Funktionen und speziell, wenn Sie die Funktion innerhalb der Klassendefinition definieren, beeinflusst sie das Nachschlagen ziemlich. –

2

forward-Deklaration muss nicht an der Spitze der Datei wie folgt

class A; 
class C; 
class D; 
class B 
{ 
    A* a; 
    C* c; 
    D* d; 
}; 

das gleiche ist wie

class B 
{ 
    class A* a; 
    class C* c; 
    class D* d; 
}; 

die empfohlene Freund Syntax verwendet nur die späteren

+1

Für Freundesdeklarationen ist es in C++ 03 nicht * empfohlen *, sondern * erforderlich * und hat in C++ 11 eine etwas andere Bedeutung (wobei 'Freundklasse X' nicht für Vorlagenparameter verwendet werden kann) –