define cpp compile classes c++ header include code-organization

compile - include cpp c++



Orden de encabezado C++ (10)

¿Qué orden deberían declararse los encabezados en un archivo header / cpp? Obviamente, los que son requeridos por los encabezados posteriores deben ser anteriores y los encabezados específicos de clase deben estar en el alcance de cpp, no en el ámbito del encabezado, pero, ¿existe una convención / mejor práctica de orden establecida?


Buena práctica: cada archivo .h debe tener un .cpp que incluya esa .h antes que cualquier otra cosa. Esto demuestra que cualquier archivo .h se puede poner primero.

Incluso si el encabezado no requiere implementación, usted crea un archivo .cpp que solo incluye ese archivo .h y nada más.

Esto significa que puede responder a su pregunta de la forma que desee. No importa en qué orden los incluyas.

Para obtener más consejos, pruebe este libro: Diseño de software en C ++ a gran escala : es una pena que sea tan caro, pero es prácticamente una guía de supervivencia para el diseño del código fuente de C ++.


El "cómo" no es obvio, pero es el "qué". Su objetivo es asegurarse de que el orden en el que incluye los archivos de encabezado nunca importe (y me refiero a "¡NUNCA!").

Una buena ayuda es comprobar si los archivos de encabezado compilan al compilar archivos cpp (uno para cada archivo de encabezado) que solo incluyen uno de ellos.


En los archivos de cabecera, tiendo a poner encabezados estándar primero, luego mis propios encabezados (ambas listas se ordenan alfabéticamente). En los archivos de implementación, coloco primero el encabezado correspondiente (si corresponde), luego los encabezados de estándares y otros encabezados de dependencia.

El orden es de poca importancia, excepto si hace un gran uso de macros y #define ; en ese caso, debe verificar que una macro que definió no reemplace a una incluida previamente (excepto si eso es lo que desea, por supuesto).

Con respecto a esta declaración

aquellos que son requeridos por los siguientes encabezados deben ser anteriores

¡Un encabezado no debe depender de otros encabezados que se incluyan antes! Si requiere encabezados, solo los incluye. Los protectores de encabezado evitarán la inclusión múltiple:

#ifndef FOO_HEADER_H #define FOO_HEADER_H ... #endif

EDITAR

Desde que escribí esta respuesta, cambié mi forma de ordenar las directivas de inclusión en mi código. Ahora, intento poner siempre los encabezados en un orden creciente de estandarización, por lo que los encabezados de mi proyecto son los primeros, seguidos por los encabezados de las bibliotecas de terceros, seguidos de los encabezados estándar.

Por ejemplo, si uno de mis archivos usa una biblioteca que escribí, Qt, Boost y la biblioteca estándar, ordenaré los siguientes de la siguiente manera:

//foo.cpp #include "foo.hpp" #include <my_library.hpp> // other headers related to my_library #include <QtCore/qalgorithms.h> // other Qt headers #include <boost/format.hpp> // Boost is arguably more standard than Qt // other boost headers #include <algorithms> // other standard algorithms

La razón por la que hago eso es para detectar dependencias faltantes en mis propios encabezados: supongamos, por ejemplo, que my_library.hpp usa std::copy , pero no incluye <algorithm> . Si lo foo.cpp después de <algorithm> en foo.cpp , esta dependencia faltante pasará desapercibida. Por el contrario, con el orden que acabo de presentar, el compilador se quejará de que no se ha declarado std::copy , lo que me permite corregir my_library.hpp .

En cada grupo de "biblioteca", trato de mantener las directivas de inclusión ordenadas alfabéticamente, para encontrarlas más fácilmente.

En una nota al margen, una buena práctica es también limitar al máximo la dependencia entre los archivos de encabezado. Los archivos deben incluir la menor cantidad de encabezados posible, especialmente el archivo de encabezados. De hecho, cuantas más cabeceras incluya, más código necesitará ser recompilado cuando algo cambie. Una buena forma de limitar estas dependencias es usar la declaración directa, que a menudo es suficiente en los archivos de encabezado (consulte ¿ Cuándo puedo usar una declaración directa? ).


En un archivo de encabezado, debe incluir TODOS los encabezados para hacerlo compilable. Y no te olvides de usar declaraciones directas en lugar de algunos encabezados.

En un archivo fuente:

  • archivo de encabezado correspondiente
  • encabezados de proyectos necesarios
  • Encabezados de bibliotecas de terceros
  • encabezados de bibliotecas estándar
  • encabezados del sistema

En ese orden, no perderá ninguno de sus archivos de encabezado que olvidó incluir las bibliotecas por su cuenta.


Encontré la siguiente convención la más útil:

module.cpp:

// this is the header used to trigger inclusion of precompiled headers #include <precompiled.h> // this ensures that anything that includes "module.h" works #include "module.h" // other headers, usually system headers, the project

Lo importante es colocar el encabezado del módulo como el primer encabezado no precompilado. Esto garantiza que "module.h" no tenga dependencias inesperadas.

Si está trabajando en un proyecto grande con tiempos de acceso lento al disco, he visto que este estilo se usa para disminuir los tiempos de compilación:

module.cpp:

// this is the header used to trigger inclusion of precompiled headers #include <precompiled.h> // this ensures that anything that includes "module.h" works #include "module.h" // other headers, usually system headers, the project #if !defined _OTHER_MODULE_GUARD_ #include "other_module.h" #endif #if !defined _ANOTHER_MODULE_GUARD_ #include "another_module.h" #endif

Es un poco detallado, pero guarda en la búsqueda de disco, ya que el encabezado no se buscará / abrirá si ya se ha incluido. Sin la verificación de guardia, el compilador buscará y abrirá el archivo de encabezado, analizará todo el archivo para terminar #ifdef el archivo completo.


Es una cuestión de dependencia y depende en gran medida de lo que pones en nuestros encabezados. Un hecho es que puedes ser realmente notorio al respecto y minimizar para mantener el include estricto, pero eventualmente te encontrarás con un escenario en el que querrás usar guardias de inclusión.

#ifndef MY_HEADER_H #define MY_HEADER_H //... #endif

El problema no es tan evidente al principio, pero a medida que aumenta la complejidad de su software, también lo hacen sus dependencias. Puede hacerlo bien y ser inteligente al respecto, pero los proyectos más grandes de C ++ generalmente están plagados de inclusiones. Puedes intentarlo, pero solo puedes hacer tanto. Así que sé diligente y piensa en tu incluye, ¡SÍ! Pero seguramente tendrá dependencias cíclicas en algún momento y es por eso que necesita guardias de inclusión.


Para los archivos .cpp, debe incluir el encabezado de la clase o lo que sea que esté implementando primero, de modo que vea el caso en el que falta este encabezado. Después de eso, la mayoría de las pautas de codificación tienden a incluir encabezados de sistema primero, encabezados de proyecto en segundo lugar, por ejemplo, la Guía de estilo de Google C ++ .


Si un encabezado necesita otros encabezados, simplemente los incluye en ese encabezado.

Intente estructurar su código para que apruebe punteros o referencias y adelante declare donde pueda.

En la implementación, el encabezado que la define debe aparecer primero (excepto en Visual Studio si usa pch, entonces stdafx iría primero).

Generalmente los enumero como lo necesito.


Solía ​​ordenarlos en orden alfabético (más fácil de encontrar)


Guía de estilo de Google C ++, nombres y orden de incluye :

En dir / foo.cc, cuyo objetivo principal es implementar o probar las cosas en dir2 / foo2.h, pida sus includes de la siguiente manera:

  • dir2 / foo2.h (ubicación preferida - ver detalles a continuación).
  • C archivos de sistema.
  • Archivos del sistema C ++.
  • Otros archivos .h de bibliotecas.
  • Los archivos .h de su proyecto.