2012-03-27 6 views
10

Niedawno dowiedziałem się o koncepcji friend class w C++ (trochę googlowałem, ale ta answer rozśmieszyło mnie, dopóki nie przypomniałem sobie najważniejszych części) i próbuję włączyć to do projektu Pracuję teraz. Na końcu zwięzłe pytanie jest wyróżnione, ale ogólnie jestem zdezorientowany przez kompletny brak przyszłych zgłoszeń w moim działającym kodzie.W jaki sposób deklaracja przyszłości nie jest potrzebna w przypadku koncepcji klasy przyjaciół?

Wszystkie moje zajęcia są oddzielone przez (pod) folderów, a każdy z nich w oddzielnym .h i .cpp pliku, ale to powinno wystarczyć, aby uzyskać wrażenie o zależności:

// 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! 
} 

Teraz, miałem imprezę, zbierając to wszystko, aby faktycznie skompilować wszystkie zależności (musiałem to zapisać na diagramie klasy, aby to działało), ale teraz to robi. Fakt, że w rzeczywistości mylące mnie, jest to, że nie były potrzebne deklaracje forward. Wiem o wcześniejszych deklaracjach forward i na wszelki wypadek odświeżyłem swoją pamięć this answer.

Tak, aby spróbować zachować to jasne, moje pytanie: Podczas deklarowania class TLS jako przyjaciela, to dlaczego były potrzebne żadne wyraźne deklaracje forward? Czy to oznacza, że ​​deklaracja friend class jest deklaracją naprzód w niej samej? Dla mnie intuicyjnie czegoś tu brakuje ... A skoro kompiluje się i działa normalnie, czy ktoś może poprawić moją intuicję? : D

PS przepraszam za tak długie wprowadzenie do pytania i garść kodu. Proszę nie komentować mojej koncepcji kodu - przyjaciele są tutaj dobrzy, jestem prawie pewien, że to jest poprawne dla mojego obecnego projektu (jest to trochę trudne do zobaczenia z tego szkieletu). Chciałbym tylko wiedzieć, dlaczego nigdzie nie potrzebna była żadna deklaracja.

Odpowiedz

6

Zgadza się, deklaracja przyjaciela jest jak deklaracja terminowa.

Poniższe kompiluje:

class A; 
class B 
{ 
    friend A; 
}; 

lub

class B 
{ 
    friend class A; 
}; 

nie:

class B 
{ 
    friend A; 
}; 

To nie faktycznie deklaracja friend że przyszłościowe deklaruje class A, ale class ke Yword. Dlatego drugi przykład nie działa, ponieważ nie wie, co to jest A. Jeśli wcześniej zadeklarujesz A, tak jak w pierwszym fragmencie, może on zastąpić A deklaracją klasy.

I stand corrected.

+0

Hm. Dziwne. Mam taką sytuację, którą powiedziałeś * nie * kompiluje się w mojej wersji kodu (znajduje to tutaj odzwierciedlenie w fakcie, że FE nie przekazuje dalej deklarowania TLS, lub włącza go w ogóle) - i to działa! To mnie myli! Ach, a także, zauważyłem, że użyłeś składni "przyjaciel A" zamiast "przyjaciel klasy A". Czy mógłbyś to rozwinąć, czy przypadkiem udało mi się scalić deklarację napastnika i przyjaciela w jeden? – penelope

+1

Uwaga: Pierwszy fragment kodu nie zostanie skompilowany w C++ 03 (dla tych, które nie mogą jeszcze używać C++ 11). Drugi fragment nie kompiluje się z g ++ 4.5 lub clang ++ 3.0 (nawet w trybie C++ 11). –

+0

@Luchian Jestem zdezorientowany, jak skompilowałeś swój drugi przykład? To skłoniło mnie do zadawania tego pytania, które wydaje się wskazywać na twój drugi przykład nie powinien się kompilować: http://stackoverflow.com/questions/14114956/friend-declaration-not-forward-declaring – JaredC

0

Czy to znaczy, że deklaracja jest klasa przyjaciel naprzód deklaracja wszystko w nim siebie?

Tak

7
friend class TLS; 

Ta składnia jest oświadczenie w sobie, dlatego nie ma potrzeby dodatkowego poprzednią deklarację typu. Zauważ, że deklaracja friend jest nieco inna (specjalnie dla funkcji) niż deklaracja w otaczającej przestrzeni nazw.

W szczególności, jeśli nie ma również deklaracji w otaczającej przestrzeni nazw, funkcja zadeklarowana w deklaracji friend może zostać znaleziona tylko przez wyszukiwanie zależne od argumentu (i nie może być zdefiniowane poza klasą). To samo dotyczy klas, chyba że istnieje również deklaracja na poziomie przestrzeni nazw, tak deklarowany typ nie będzie dostępny poza klasą deklarującą go jako znajomego.

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

Zastanawiałem się, dlaczego nie muszę jawnie zadeklarować 'TLS' w' FE' i 'SD', ale jest to dużo nowych informacji. Co zasugerowałeś (deklarując typy * only * w treści innej klasy), prawdopodobnie zostałoby użyte do implementacji wewnętrznych funkcji narzędziowych klasy lub takich? – penelope

+0

@penelope: Myślę, że to tylko efekt uboczny tego, jak wykonywane jest wyszukiwanie. Nie zastanawiałem się zbytnio nad typami, gdzie wydaje się to oznaczać * istnieje typ A, który ma dostęp do tej klasy * i nic więcej (tzn. Nie możesz użyć 'A' jako właściwego typu nawet wewnątrz' B'). Ale w przypadku funkcji, a konkretnie, jeśli zdefiniujesz funkcję wewnątrz definicji klasy, będzie ona wyglądała dość mocno. –

2

naprzód deklaracja nie musi znajdować się na początku pliku następująco

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

jest taka sama jak

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

zalecana składnia przyjaciel właśnie wykorzystuje później

+1

Dla deklaracji znajomych nie jest * zalecane *, ale * wymagane * w C++ 03, i ma nieco inne znaczenie w C++ 11 (gdzie i 'przyjaciel klasa X' nie może być używane w odniesieniu do parametrów szablonu) –

Powiązane problemy