2010-10-14 20 views
10

En Efectivo C++ (3ª edición), Scott Meyers, en el Ítem 31, sugiere que las clases deberían tener, además de su declaración clásica (. h) y archivos de definición (.cpp), un archivo Forward Declaration Include (fwd.h), qué clase que no necesita la definición completa puede usar, en lugar de declararse hacia adelante.La declaración directa incluye, además de la declaración, incluir (ClassFwd.h + Class.h)

De alguna manera veo el caso, pero realmente no veo esto como una opción viable ... Parece muy difícil de mantener, más bien exagerado y apenas necesario.

Sin embargo, puedo ver su uso para declaraciones de plantilla hacia adelante, que son bastante pesadas. Pero para las clases simples? Parece que es difícil de mantener y creará una gran cantidad de archivos de inclusión casi vacíos que sirven para un propósito muy pequeño ... ¿vale la pena la molestia?

Aquí está un ejemplo:

// Class.h 
class Class 
{ 
    Class(); 
    ~Class(); 
}; 

// ClassFwd.h 
class Class; 

// Class.cpp 
Class::Class() 
{ 
} 

Class::~Class() 
{ 
} 

Mi pregunta:

¿Qué piensan ustedes? Si esta es una buena práctica?

NOTA Estoy más que interesado en los argumentos PARA ESTA práctica, para ver si me perdí algo que me haría estar de acuerdo con Scott Meyers.

Respuesta

6

que utiliza archivos de cabecera hacia delante declaración para todos mis bibliotecas Una biblioteca tendría típicamente esta estructura:..

lib/ 
    include/ 
    class headers + Fwd.h 
src/ 
    source files + internal headers 

el directorio lib/include contendría todas las cabeceras de las clases públicas junto con uno header declaraciones adelantadas esto hizo que la luz- biblioteca peso en el lado de inclusión. Cualquier encabezado fuera de esta biblioteca solo incluye el encabezado directo (Fwd.h), mientras que las fuentes externas a esta biblioteca incluyen el co necesario mplete encabezados. También se puede proporcionar un encabezado de conveniencia (Lib.h) que incluye todos los demás encabezados, para usar en archivos fuente.

Otra cosa para colocar en el encabezado de declaración directa es typedef s para shared_ptr, especialmente en el caso de una jerarquía de herencia con clases de fábrica que devuelven punteros a las implementaciones.

Lo anterior es útil para aplicaciones más grandes con muchas bibliotecas internas. Un refinamiento de lo anterior para este caso sería colocar los encabezados públicos en lib/include/lib. De esta forma, los clientes de su biblioteca deberían incluir lib/.... Piense en esto como un espacio de nombres para sus encabezados.

¡Buena suerte!

+1

Gracias por la respuesta, sin embargo, usted está simplemente diciendo lo que hace, no por qué lo hace. El único argumento que proporciona es para shared_ptr, que ya resolví teniendo una macro FORWARD_SHARED(), que reenvía declara una clase y su puntero automáticamente. Esto es muy liviano y fácil de leer ... – Geeho

+0

Ok, la razón es para reducir el tiempo de compilación y centralizar las declaraciones hacia adelante. Si todas las declaraciones avanzadas están en un archivo, es fácil agregar nuevas cuando se realicen nuevas clases. Lo mismo con puntero typedefs. Por qué el tiempo de compilación es reducido debería ser obvio. ¿Tiene sentido esto para ti? Mantener los archivos de encabezado limpios de cualquier cosa que no sean declaraciones anticipadas ayudará a medida que su base de código crezca. –

+2

¡Ah! ¡Entonces tienes un único archivo Fwd.h! ¡No uno por encabezado! Ahora veo cómo puede tener sentido ... Muy bien, reflexionaré sobre eso por un tiempo ... – Geeho

0

Si usted tiene una gran solución de esto es su única oportunidad de manejar las dependencias inherentes:

struct A { 
    B* m_pB; 
}; 

struct B { 
    A* m_pA; 
}; 

Ahora A y B pueden ser razonablemente en diferentes archivos de cabecera, tal vez incluso diferentes proyectos. Sin embargo, su dependencia no es un defecto de diseño sino completamente lógica y necesaria. ¿Qué haces?

  1. Primero incluya un único encabezado Types.h forward-declarating para cada uno de los proyectos requeridos, es decir, la declaración forward no tiene su propio archivo de encabezado por clase.
  2. Luego incluya Class.h de todos los proyectos requeridos. Estos encabezados requerirán declaraciones futuras para compilar.
  3. Incluya los encabezados del proyecto principal.

En una solución bastante grande (500k LOC) he encontrado que este patrón es muy fácil de manejar. De lo contrario, si cambia una declaración de clase, ¿dónde encuentra todas las declaraciones de reenvío que puede haber hecho individualmente en cualquier cantidad de otros archivos de encabezado?

+0

Su ejemplo parece ser un caso para la declaración directa en general, no para los archivos fwd.h en particular. – Geeho

2

La colocación de un simple class Whatever; en su propio encabezado no tiene ventajas y muchas desventajas.

Especialmente en el caso en que el acceso a un encabezado puede llevar mucho tiempo, se usan declaraciones de reenvío simples para evitar el acceso a los encabezados; ponerlos en sus propios encabezados sería frustrar el propósito ...

Con las cosas con plantilla, como se nota, es un asunto diferente. P.ej. echa un vistazo a <iosfwd> de la biblioteca estándar.

Cheers & hth.

+0

Mi problema es que estoy de acuerdo contigo, pero no con Meyers. Puede ser la respuesta que estoy buscando, ¡pero quiero que mi opinión sea cuestionada! : D – Geeho

+0

Con el almacenamiento en memoria caché de disco moderno, el tiempo de compilación (y la memoria) afectados al acceder a un encabezado no se basa tanto en el número de encabezados sino en la complejidad del código interno. Incluir un encabezado mucho más simple en lugar de la definición completa no derrota el propósito en absoluto, entonces. –

+0

@BenVoigt: re "Incluyendo un encabezado mucho más simple en lugar de la definición completa", la pregunta es * incluyendo un encabezado * frente a * escribiendo simplemente 'clase X;' *. El primero implica al menos un acceso de disco adicional. Hay una razón para construir granjas. –

1

La práctica permite al usuario del código no pensar si una clase es regular o plantilla. El usuario simplemente #inluye "correspondiendo_fwd.h "file y tiene una referencia de clase. Una molestia menos para el usuario es A Good Thing. Pero si es un proyecto pequeño o el creador de la clase es el usuario de la única clase, entonces podría ser más molestia. Depende.

+0

Ok, veo tu punto. Todavía soy un poco escéptico de que valga la pena, teniendo en cuenta el esfuerzo extra. Parece que si fuera solo un usuario, estaría bien, pero si también soy un dev, entonces el tiempo o la energía que guardo, incluido fwd.h sin pensar, se compensa con el tiempo perdido al crearlos ... – Geeho

Cuestiones relacionadas