2011-07-22 24 views
5

Duplicar posibles:
Proper way to #include when there is a circular dependency?Mutual incluir en C++ .. ¿cómo funciona?

estoy bastante nuevo en C++ y tienen la pregunta planteada en el título. O más precisamente: si A.h incluye B.h y B.h incluye A.h, recibo un mensaje de error porque "incluir # archivo" C: ... \ A.h "se incluye a sí mismo". Archivo: B.h

No pude encontrar una forma de evitar esto, y mi configuración general requiere bastante esa relación entre esas clases. ¿Hay alguna posibilidad de que esto funcione?

+0

Buena pregunta. Los preprocesadores trabajan línea por línea, estudiarás cómo funcionan '# ifdef',' # define' y '# endif' :-) – Stan

Respuesta

6

Simple: no dejes que A.h incluya B.h. Y viceversa.

En general, los archivos de encabezado deben incluir tan poco como sea posible. Puede usar la declaración de reenvío para obtener una gran cantidad de inclusiones. La única vez que debe incluir absolutamente algo en un encabezado es si hay objetos que se utilizan como no referencias en ese encabezado.

Así que evita hacer eso. Use Pimpl para evitar poner a los miembros de la clase en los encabezados. Y a menos que sea un código de plantilla o necesite el soporte de inicialización, no escriba el código real en los encabezados.

El peor caso es que tendrá que crear un C.h que defina lo que A.h y B.h necesitan.

+1

TIL: delcaration hacia adelante =) – ArniBoy

+0

Gracias @Nicol, ese es un buen punto. En general (no en este caso específico de inclusión doble), ¿puede explicar por qué prefiere una declaración directa a una inclusión normal? – Enzo

7

Utilice Incluir guardias en sus archivos de encabezado. http://en.wikipedia.org/wiki/Include_guard

#ifndef MYHEADER_H 
#define MYHEADER_H 

//add decls here 

#endif 

De esta manera si sus archivos de cabecera se incluyen más de una vez el compilador los ignora.

También como regla general si incluye B.h que tiene A.h, sería mejor incluir A.h y B.h en su aplicación en lugar de confiar en la inclusión de B.h.

También solo ponga declaraciones en el archivo de encabezado.

Evite las definiciones a toda costa en los archivos de encabezado.

0

trate de añadir guardias de cabecera,

#ifndef _A_H_ 
#define _A_H_ 
... 
.. 
. 
#endif /* #ifndef _A_H_ */ 

Nunca se debe incluir un archivo de cabecera dos veces, se traduce en la redefinición ..

0

Cuando se añade un archivo de cabecera en un archivo que se incluye en el apartado de preproceso de compilación. Así que incluye B.h en A.h. E incluyendo A.h en B.h. Es infinitamente recursivo y el archivo se incluye varias veces.

Incluyendo B.h en A.h asciende a A.h < - B.h Incluyendo A.h en B.h asciende a Bh < - A.h

Por lo que su rey de bucle recursivo infinito.

1

Usted no dijo cuáles son esas dependencias mutuas, por lo que estas son solo conjeturas. En todos estos supongo que A.h define class A y B.h definió class B.

Caso 1: La dependencia mutua es a través de punteros o referencias. Por ejemplo, class A contiene un miembro de datos del tipo B* y viceversa. En este caso, ninguno de los encabezados necesita #include el otro. Use una declaración hacia adelante en su lugar.

Caso 2: La dependencia mutua es a través de los objetos. Por ejemplo, class A contiene un miembro de datos del tipo B y viceversa. En este caso, eres una manguera.

Caso 3: Dependencias mixtas.
Por ejemplo, class A contiene un miembro de datos del tipo B pero class B contiene un miembro de datos del tipo A*. Ahora A.h necesita #include B.h, pero B.h simplemente necesita una declaración directa de class A.

Siempre debe usar algún tipo de protector de inclusión de una sola vez para evitar que se incluya un encabezado varias veces.

1

Suponiendo que en cada cabecera tiene una clase, puede hacerlo de esta manera:

Archivo de cabecera: "Ah"

#ifndef A_H 
#define A_H 
Class B; 

Class A { 
public: 
    B name_of_B_; 
} 

#endif 

Con #ifndef A_H #define A_H #endif se asegura de que cada cabecera se incluye sólo una vez . Debe usar esto en casi todos los archivos de encabezado que produzca, no solo en este caso especial de doble inclusión. Con Class B; declaras que en algún lugar se definirá una clase llamada "B".

Class B { 
public: 
    A name_of_A_; 
} 

#endif 

La misma historia que para la clase "B". De esta forma evitará la inclusión de bucle infinito.

+1

Las inclusiones presentes al final de cada archivo de encabezado son completamente inútiles. Declaración a plazo como Clase A; es un mecanismo para decirle al compilador que una Clase A estará presente más tarde, lo mismo para la Clase B. En este punto, no importa cuándo se resolverá cualquiera de Clase A o B, porque usted acaba de decirle al compilador que ambos estarán allí al final de la compilación usando la declaración forward. Por lo tanto, las inclusiones al final del archivo de encabezado se pueden eliminar porque no sirven para nada. Saludos;) – ForceMagic

+0

¡Correcto! Gracias por mencionarlo. – Enzo

Cuestiones relacionadas