2012-09-06 9 views
5

¿Por qué declarar la clase que incluyó como archivo de encabezado?¿Por qué declarar la clase que incluyó como un archivo de encabezado?

#include "TreeCallObj.h" 
#include "TreeDevObj.h" 
#include "TreeDevCallObj.h" 

class TreeCallObj; //what is the purpose of this line ? 
class TreeDevObj; //what is the purpose of this line ? 
class TreeDevCallObj; //what is the purpose of this line ? 


class Apple 
{ 
public: 
... 
private: 
... 
} 
+1

Parece que nos falta algo de contexto. ¿Posiblemente hay alguna referencia circular al archivo de encabezado, y las clases 'TreeWhateverObj' son referidas por un puntero solo en el archivo actual? Tal vez fue escrito por alguien a quien realmente le gustan sus definiciones avanzadas. El sufijo de nombres de clase en 'Obj' me parece una loca alerta de convención de codificación. – Rook

+0

He leído que declarar que la clase puede mejorar el tiempo de compilación si el proyecto tarda 10 minutos en compilarse. No sé cuán cierto es esto y cuánto beneficio. – jdl

+0

Suena bastante poco probable, pero también bastante sencillo de probar. Háganos saber cómo va ;-) – Rook

Respuesta

6

Considera:

//a.h 
#ifndef A_H 
#define A_H 

#include "b.h" 
class A 
{ 
    B* b; 
}; 
#endif 

//b.h 
#ifndef B_H 
#define B_H 

#include "a.h" 
class B 
{ 
    A* a; 
}; 
#endif 

Ahora intenta incluir uno de los archivos en una diferente, que dicen #include "a.h".

El compilador analizar como:

#ifndef A_H 
#define A_H 

bien - A_H no se define

#include "b.h" 

oportunidad para pegar el contenido:

#ifndef B_H 
#define B_H 

ok, ya B_H ISN '0 definido

#include "a.h" 

esto no definirá A, porque A_H está definido.Así que la próxima, tenemos

class B 
{ 
    A* a; 
}; 

que dará lugar a un error, porque no se definió A o anunciados antes de la utilización.

La declaración forward corrige esto.

Por supuesto, la mejor solución para esto es no incluir nada (a menos que sea absolutamente necesario).

+1

No.Si en el tercer caso ya se ha definido 'A_H', entonces la clase' A' ya se habría definido también para ese mismo alcance. –

+0

@EitanT no, porque A.h incluye B.h antes de que se defina A. ¿Derecha? –

+0

"esto no definirá A, porque A_H está definido. Entonces, a continuación, tenemos" - sí, y ese es el punto de las guardias de inclusión. Si se define 'A_H', entonces la clase A ya está declarada, sin error. –

3

Si en los archivos hay definición de clases, por lo que, forward declaration es innecesario en los casos normales.

5

¿Cuál es el propósito de esta línea?

Idealmente nada. Es superfluo

Sin embargo, como señaló @Luchian Grigore, puede haber un código mal diseñado que, debido al uso incorrecto de incluir guardias e inclusiones cruzadas, las declaraciones directas pueden ser necesarias.

+0

@LuchianGrigore sí. Usted tenía razón. –

+0

No necesariamente es código mal diseñado. Es solo una dependencia circular. –

+0

@EitanT Bueno, creo que sí. Si uno no puede resolver un problema sin referencias cruzadas, hay un problema en el diseño. ¿Podría darnos un ejemplo en el que cree que es un buen enfoque a seguir? –

1

Ninguna razón en absoluto. Necesitas hacer uno u otro, dependiendo de la situación, pero no ambos.

0

Si sus archivos de cabecera son correctos veo ninguna razón para declarar porque ya deben declarada en la cabecera

1

En su forma actual, no hay necesidad.

Sin embargo, esto puede haber evolucionado históricamente: En algún momento, un tipo incompleto puede haber sido suficiente:

class Foo; 

struct Gizmo 
{ 
    void f(Foo); 
}; 

Entonces, en un momento posterior, el autor decidió que necesitaba el tipo completo:

#include "Foo.hpp" 

class Foo; 

struct Gizmo 
{ 
    void f(Foo); 
    Foo x; 
}; 

el código original sólo puede haber sido modificado con la inclusión de cabecera, ahora es necesario ...

+0

O bien, 'struct Gizmo {Foo * foo; } 'que luego se cambia a' struct Gizmo {Foo foo; } ' Entonces, para el primero, una declaración 'clase Foo;' es suficiente, pero para este último se necesita la definición, por lo tanto, '#include" foo.hpp "'. :-) – Nawaz

+0

@Nawaz: ¡Sí! Pero no quería sugerir a nadie que 'Foo *' es aceptable C++ :-) Estuve jugando momentáneamente con 'unique_ptr '... –

+0

Cuando hablas de * históricamente *, entonces puedes hablar sobre' Foo * '* cómodamente * ;-). Nadie te rechazará: P (Bueno, al menos no yo). – Nawaz

1

yo supongo que hay un poco de historia a este. Originalmente, el codificador intentó no incluir los archivos de encabezado y utilizó declaraciones directas. Luego, cuando el código se expandió, descubrieron que necesitaban los archivos de encabezado después de todo, pero no se molestaron en borrar las declaraciones de reenvío.

Como otros han dicho que no tiene sentido tener una declaración directa después de la declaración de clase.

1

Me di cuenta de que su encabezado no tiene protecciones contra la inclusión múltiple. También es posible que algunos de los otros encabezados incluidos (los encabezados usualmente tengan tales guardias) incluyan ese encabezado atrás. Como resultado, no compiló. Entonces alguien agregó declaraciones avanzadas para corregir el error equivocado.

Cuestiones relacionadas