2010-08-21 11 views
5
#include "DLLDefines.h" 
#include "DLLDefines.h" 

Lo anterior realmente pasó la compilación, pero ¿por qué?¿Por qué es válido incluir un archivo de encabezado dos veces en C++?

+7

¿Por qué no sería válido? (Pregunta seria, tratando de ver cómo entiendes '# include'.) – strager

+0

Para seguir en el punto de Straight:' # include' pega los contenidos del archivo incluido en el archivo actual. Nada más (aparte de quizás algunas anotaciones específicas de implementación para ayudar al compilador a informar los números de línea para errores y para emitir información de depuración). No hay ninguna razón en particular para prohibirte hacer eso dos veces, y los archivos '.h' de buen comportamiento lo soportan usando guardias de inclusión. –

Respuesta

4

Probablemente tenga #define en DLLDefines.h alrededor de su código que impida que se incluya dos veces.

#ifndef DLLDEFINES_H 
#define DLLDEFINES_H 
// your code 
#endif 
+7

Nitpick: esta técnica no impide que se incluya dos veces; hace que sea seguro incluirlo varias veces. –

+1

@Charles: evita que el código en el encabezado se lea dos veces, que es lo que normalmente significa incluir un archivo. – rubenvb

+0

De hecho, no estaba seguro de cómo decirlo sin complicar demasiado la explicación. El preprocesador ignorará el contenido dentro del #ifndef la segunda vez que se incluye el archivo. – Zaki

8

Depende del archivo de encabezado; no hay restricción de idioma en múltiples incluye del mismo archivo.

Algunos archivos están diseñados para incluirse varias veces (por ejemplo, <assert.h> se pueden incluir varias veces para activar o desactivar 'assert).

Muchos archivos son seguros para ser incluidos varias veces porque tienen incluyen guardias, otros no son y deben incluirse solo una vez en una unidad de traducción o incluso en un programa.

6

incluir no tiene nada que ver con el lenguaje C o C++. Es una directiva para el preprocesador traer un archivo. Al preprocesador no le importa qué archivo se trae y no debería. Podría ser perfectamente aceptable para hacer esto:

void Foo::SomeFunc(int cond) 
{ 
    switch (cond) { 
    case kThisCase: 
#include "longFirstCase.h" 
     break; 
    case kSecondCase: 
#include "longSecondCase.h" 
     break; 
    case kThirdCase: 
#include "longFirstCase.h" 
#include "longSecondCase.h" 
     break; 
    } 
} 

he visto el mismo archivo incluye varias veces como un mecanismo de configuración también.

De acuerdo, hay una serie de formas de factorizar ese ejemplo que son mejores, pero el hecho es que puede haber razones perfectamente buenas por las que desearía y, por lo tanto, no hay restricciones en el uso.

+1

¿Cómo espera que esto funcione? # ¿Incluye cosas que dependen de la información de tiempo de ejecución? – Shautieh

+1

@Shautieh, '# include' inserta el archivo fuente textualmente. Es de suponer que los archivos 'longFirstCase.h' y' longSecondCase.h' contienen código C destinado a estar dentro de la instrucción 'switch'. – strager

+0

@Shautieh como dijo strager, pega el código en el archivo donde está escrito #include. Como ejemplo, esta técnica se usa a menudo para incluir partes de código autogenerado. –

1

Se llama include guard.

#ifndef GRANDFATHER_H 
#define GRANDFATHER_H 

struct foo { 
    int member; 
}; 

#endif 

Cita de Wikipedia:

In the C and C++ programming languages, an #include guard, sometimes called a macro guard, is a particular construct used to avoid the problem of double inclusion when dealing with the #include directive. The addition of #include guards to a header file is one way to make that file idempotent.

Ver enlace anterior para obtener más información.

2

Siempre que la inclusión múltiple de archivos de encabezado no viole ODR (Regla de definición única) $ 3.2, el código está bien formado.

0

DLLDefines.h también puede tener #pragma una vez en la parte superior , #pragma una vez asegura que el archivo se incluye una sola vez.

+0

Esa es una extensión única de Microsoft, IIRC. – JustBoo

+0

@JustBoo Según [Wikipedia] (http://en.wikipedia.org/wiki/Pragma_once#Portability), la mayoría de los compiladores admiten '#pragma una vez' – Angew

12

Bueno, es legal porque tiene para ser legal. Porque a menudo incluye el mismo encabezado varias veces sin siquiera darse cuenta.

Puede incluir dos encabezados en un archivo .cpp, cada uno de los cuales incluye una cantidad de archivos, algunos de los cuales pueden estar incluidos por ambos.

Por ejemplo, todos los encabezados de biblioteca estándar (por ejemplo, string o vector por ejemplo) están probablemente incluidos en la mayoría de sus encabezados. Así que rápidamente termina con el mismo encabezado indirectamente incluido varias veces en el mismo archivo .cpp.

Así que en resumen, tiene para funcionar, o todos los códigos C++ se desmoronarían.

En cuanto a cómo funciona, generalmente a través de incluye guardias. Recuerde que #include solo realiza un simple copiar/pegar: inserta el contenido del archivo de encabezado en el sitio #include.

Así que digamos que usted tiene un archivo de cabecera header.h con el siguiente contenido:

class MyClass {}; 

Ahora vamos a crear un archivo CPP que incluye dos veces:

#include "header.h" 
#include "header.h" 

el preprocesador se expande esto a:

class MyClass {}; 
class MyClass {}; 

que obviamente causa un error: se define la misma clase d dos veces. Entonces eso no funciona. En su lugar, vamos a modificar el encabezado para contener incluyen guardias:

#ifndef HEADER_H 
#define HEADER_H 

class MyClass {}; 

#endif 

Ahora, si incluimos dos veces, obtenemos lo siguiente:

#ifndef HEADER_H 
#define HEADER_H 

class MyClass {}; 

#endif 

#ifndef HEADER_H 
#define HEADER_H 

class MyClass {}; 

#endif 

y esto es lo que sucede cuando el preprocesador procesa:

#ifndef HEADER_H // HEADER_H is not defined, so we enter the "if" block 
#define HEADER_H // HEADER_H is now defined 

class MyClass {};// MyClass is now defined 

#endif   // leaving the "if" block 

#ifndef HEADER_H // HEADER_H *is* defined, so we do *not* enter the "if" block 
//#define HEADER_H 
// 
//class MyClass {}; 
// 
#endif   // end of the skipped "if" block 

Por lo tanto, el resultado final es que MyClass obtuve define sólo una vez , e aunque el encabezado se incluyó dos veces. Y entonces el código resultante es válido.

Esta es una propiedad importante de los archivos de encabezado. Defina siempre sus encabezados para que sea válido incluirlos varias veces.

Cuestiones relacionadas