2010-02-19 12 views
27

Estoy leyendo un código de C++ y Observe que hay "#include" tanto en los archivos de encabezado y archivos .cpp. Supongo que si muevo todo el "#include" en el archivo, digamos foo.cpp, también su 'archivo de encabezado foo.hh y deje que foo.cpp solo incluya foo.hh el código debería funcionar de todos modos sin tener en cuenta problemas como inconvenientes, eficiencia y etc.donde debe "incluir" poner en C++

Sé que mi idea de "repentinamente" debe ser de alguna manera una mala idea, pero ¿cuáles son los inconvenientes exactos de la misma? Soy nuevo en C++, así que no quiero leer muchos libros en C++ antes de poder responder esta pregunta yo solo. así que solo deje la pregunta aquí por su ayuda. gracias por adelantado.

Respuesta

30

Como regla general, ponga sus inclusiones en los archivos .cpp cuando pueda, y solo en los archivos .h cuando eso no sea posible.

Puede eliminar forward declarations para eliminar la necesidad de incluir encabezados de otros encabezados en muchos casos: esto puede ayudar a reducir el tiempo de compilación, que puede convertirse en un gran problema a medida que su proyecto crece. Este es un buen hábito para comenzar desde el principio porque tratar de resolverlo en una fecha posterior (cuando ya es un problema) puede ser una pesadilla completa.

La excepción a esta regla son las clases de plantilla (o funciones): para usarlas, necesita ver la definición completa, lo que generalmente significa ponerlas en un archivo de encabezado.

+1

Su interpretación de "plantilla externa" es una ilusión. Estarás decepcionado. –

+0

@nobugz: ¿Ah? ¿De Verdad? Maldita sea, espero que no sea ... la velocidad de compilación de la plantilla es una de las peores cosas de C++. Ser capaz de ocultar las implementaciones de aquellos que no necesitan verlas sería una verdadera bendición. – jkp

+0

Parece que confunde la nueva plantilla externa con 'export' (que está prácticamente abandonada). http://www.cppreference.com/wiki/keywords/export – luke

5

Haría que todos los demás archivos, incluido su archivo de encabezado, incluyan transititivamente todos los #include s en su encabezado también.

En C++ (como en C) #include es manejado por el preprocesador simplemente insertando todo el texto en el archivo #include d en lugar de la declaración #include. Por lo tanto, con un montón de #include s puede literalmente alardear del tamaño de su archivo compilable a cientos de kilobytes, y el compilador necesita analizar todo esto para cada archivo. Tenga en cuenta que el mismo archivo incluido en diferentes lugares debe reparsed nuevamente en cada lugar donde está #include d. Esto puede ralentizar la compilación a un rastreo.

Si necesita declarar (pero no definir) elementos en su encabezado, use forward declaration en lugar de #include s.

+0

O, más correctamente, use la declaración directa en lugar de '# include' en sus archivos .h cada vez que pueda. A veces es inevitable. Por ejemplo, si la clase A tiene un miembro de datos de la clase B, entonces A.h deberá incluir B.h. –

1

Si #incluye los archivos .cpp, probablemente terminará con muchos errores de "definición múltiple" del vinculador. En teoría, # puede incluir todo en una sola unidad de traducción, pero eso también significa que todo debe reconstruirse cada vez que realice un cambio en un solo archivo. Para proyectos del mundo real, eso es inaceptable, por lo que tenemos enlazadores y herramientas como make.

+0

@Neil: ¡no si los encabezados están escritos correctamente! – jkp

+0

@jkp.los archivos cpp no ​​son encabezados –

+0

@Neil: mi mal. Sí, esa no es una buena práctica. – jkp

1

Incluyendo los archivos de cabecera desde el interior de los archivos de cabecera está muy bien, así que está incluida en C++ archivos, sin embargo, para minimizar los tiempos de construcción en general es preferible evitar la inclusión de un archivo de cabecera desde el interior de otro remate de cabeza a menos que sea absolutamente necesario, especialmente si muchos archivos de C++ incluyen el mismo encabezado

12

Los archivos de inclusión en un encabezado solo deben ser los necesarios para admitir ese encabezado. Por ejemplo, si su encabezado declara un vector, debe incluir vector, pero no hay razón para incluir una cadena. Debería poder tener un programa vacío que solo incluye ese único archivo de encabezado y se compilará.

Dentro del código fuente, necesita incluir todo lo que llame, por supuesto. Si ninguno de sus encabezados requiere iostream pero lo necesita para la fuente real, debe incluirse por separado.

Incluir contaminación de archivos es, en mi opinión, una de las peores formas de descomposición del código.

editar: Heh. Parece que el analizador come los símbolos> y <.

1

Se supone que los archivos .hh (o .h) son para declaraciones.

Se supone que los archivos .cpp (o .cc) son para definiciones e implementaciones.

Primero tenga en cuenta que una instrucción #include es literal. #include "foo.h" literalmente copia el contenido de foo.h y lo pega donde la directiva include está en el otro archivo.

La idea es que algunos otros archivos bar.cpp y baz.cpp quieran utilizar algún código que exista en foo.cc. La forma de hacer eso, normalmente, sería para bar.cpp y baz.cpp a #include "foo.h" para obtener las declaraciones de las funciones o clases que querían utilizar, y luego, en el momento del enlace, el enlazador conectaría estos usos en la barra .cpp y baz.cpp a las implementaciones en foo.cpp (ese es el punto principal del enlazador).

Si pones todo en foo.h y tratas de hacerlo, tendrás un problema. Digamos que foo.h declara una función llamada doFoo(). Si la definición (código para) esta función está en foo.cc, está bien. Pero si el código para doFoo() se mueve a foo.h, y luego incluye foo.h dentro de foo.cpp, bar.cpp y baz.cpp, ahora hay tres definiciones para una función llamada doFoo(), y su enlazador se quejará porque no se le permite tener más de una cosa con el mismo nombre en el mismo ámbito.

0

Puede evitar múltiples errores de definición si usa "incluir guardias".

(begin myheader.h) 
#ifndef _myheader_h_ 
#define _myheader_h_ 
struct blah {}; 
extern int whatsit; 
#endif //_myheader_h_ 

Ahora bien, si #include "myheader.h" en otros archivos de cabecera, que sólo conseguirás incluido una vez (debido a _myheader_h_ estando definido). Creo que MSVC tiene un "#pragma una vez" con la funcionalidad equivalente.

+0

'#pragma once' es ahora un estándar de facto, gcc también lo admite, y creo que otros también lo hacen. –

1

No hay nada malo con el uso de #include en un archivo de encabezado. Es una práctica muy común, no desea cargar una biblioteca a un usuario con recordar también qué otros encabezados oscuros se necesitan.

Un ejemplo estándar es #include <vector>. Obtiene la clase de vector. Y una gran cantidad de archivos internos de encabezado CRT que se necesitan para compilar correctamente la clase vectorial, cosas que realmente no necesita ni quiere saber.

1

Mientras que un archivo de encabezado debe incluir solo lo que necesita, "lo que necesita" es más fluido de lo que piensas, y depende del propósito con el que colocas el encabezado. Lo que quiero decir con esto es que algunos encabezados son en realidad documentos de interfaz para bibliotecas u otro código. En esos casos, los encabezados deben incluir (y probablemente #incluir) todo lo que otro desarrollador necesitará para usar correctamente su biblioteca.

Cuestiones relacionadas