2012-03-27 13 views
10

Acabo de enterarme del concepto friend class en C++ (he buscado en Google un poco, pero este answer me hizo reír hasta que recordé las partes más importantes), y estoy tratando de incorporarlo en el proyecto Estoy trabajando en este momento. La pregunta concisa se destaca al final, pero en general, estoy confundido por falta completa de declaraciones de envío en mi código de trabajo.¿Cómo se presenta la declaración no es necesaria para el concepto de clase amigo?

Todas mis clases están separados por carpetas (sub) y cada uno en un archivo separado .h y .cpp, pero esto debería ser suficiente para hacerse una idea acerca de las dependencias:

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

Ahora, he hecho que todo esto se compile con todas las dependencias (tuve que escribirlo en un diagrama de clase al final para que funcione), pero ahora lo hace. El hecho de que en realidad es confundiéndome, es que no se necesitan declaraciones hacia adelante. Sé de declaraciones anticipadas de antes, y por si acaso, actualicé mi memoria con this answer. Por lo tanto, para tratar de mantener en claro,

mi pregunta: Al declarar la class TLS como un amigo, ¿cómo es que no se necesitaban declaraciones adelantadas explícitas? ¿Eso significa que una declaración friend class es una declaración directa en sí misma? Para mí, intuitivamente, falta algo aquí ... Y dado que compila y funciona normalmente, ¿alguien puede ayudar a corregir mi intuición? : D

PD. Disculpe por la larga introducción a la pregunta y un montón de código. Por favor, no comenten mi concepto de código: los amigos son buenos aquí, estoy bastante seguro de que es correcto para mi proyecto actual (es un poco difícil de ver desde este esqueleto). Solo me gustaría saber por qué no se necesitaba una declaración directa en ningún lado.

Respuesta

6

Tienes razón, la declaración de amigo es una especie de declaración directa.

Los siguientes compilaciones:

class A; 
class B 
{ 
    friend A; 
}; 

o

class B 
{ 
    friend class A; 
}; 

esto no:

class B 
{ 
    friend A; 
}; 

No es en realidad la declaración friend que las proyecciones a declara class A, pero el class ke espada Es por eso que el segundo ejemplo no funciona, porque no sabe qué es A. Si declara A de antemano, como en el primer fragmento, puede resolver A en una declaración de clase.

I stand corrected.

+0

Hm. Extraño. Tengo la situación que usted dijo * no * compila en mi versión del código (se refleja aquí por el hecho de que FE no reenvía declarar TLS, o incluirlo en absoluto) - ¡y funciona! ¡Eso es lo que me está confundiendo! Ah, y también, me acabo de dar cuenta de que usaste la sintaxis 'amigo A' en lugar de 'amigo clase A'. ¿Podrías ampliar eso? ¿Conseguí accidentalmente fusionar la declaración directa y la de amigo en una sola? – penelope

+1

Nota: El primer fragmento no se compilará en C++ 03 (para aquellos que aún no pueden usar C++ 11). El segundo fragmento no se compila con g ++ 4.5 o clang ++ 3.0 (incluso en el modo C++ 11). –

+0

@Luchian ¿No entiendo cómo compiló su segundo ejemplo? Esto me llevó a hacer esta pregunta que parece indicar que su segundo ejemplo no debería compilarse: http://stackoverflow.com/questions/14114956/friend-declaration-not-forward-declaring – JaredC

0

¿Quiere decir que una declaración de clase amigo es un delantero declaración todo en si mismo?

7
friend class TLS; 

Esta sintaxis es una declaración en sí mismo, es por eso que no es necesario una previa declaración adicional del tipo. Tenga en cuenta que la declaración friend es ligeramente diferente (especialmente para funciones) que una declaración en el espacio de nombres adjunto.

En particular, a menos que también haya una declaración en el espacio de nombres adjunto, una función declarada en una declaración friend solo puede encontrarse mediante búsqueda dependiente del argumento (y no puede definirse fuera de la clase). Lo mismo ocurre con las clases, a menos que también haya una declaración a nivel del espacio de nombres, el tipo así declarado no estará disponible fuera de la clase y lo declarará como amigo.

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

Me preguntaba cómo es posible que no tuviera que declarar explícitamente 'TLS' en' FE' y 'SD', pero esta es mucha información nueva. Lo que sugirió (declarar tipos * solo * en el cuerpo de otra clase), probablemente se usaría para implementar las funciones de utilidad interna de la clase o algo así? – penelope

+0

@penelope: creo que es solo un efecto secundario de cómo se realiza la búsqueda. No le he dado mucha importancia a los tipos, donde parece significar * hay un tipo A que tiene acceso a esta clase *, y nada más (es decir, no se puede usar 'A' como un tipo apropiado incluso dentro de' B') Pero en el caso de las funciones y específicamente si define la función dentro de la definición de la clase, tiene un impacto considerable en la búsqueda. –

2

declaración adelantada no tiene por qué estar en la parte superior del archivo de la siguiente manera

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

es lo mismo que

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

la sintaxis amigo me recomendó simplemente utiliza la tarde

+1

Para las declaraciones de amigos no es * recomendado * sino * obligatorio * en C++ 03, y tiene un significado ligeramente diferente en C++ 11 (donde y 'amigo clase X' no se puede usar para referirse a parámetros de plantilla) –

Cuestiones relacionadas