Pregunta

¿En qué orden se deben declarar los encabezados en un archivo de encabezado/cpp?Obviamente, aquellos que son requeridos por los encabezados posteriores deben ser anteriores y los encabezados específicos de la clase deben estar en el alcance de cpp, no en el alcance del encabezado, pero ¿existe una convención/mejor práctica de orden establecido?

¿Fue útil?

Solución

En un archivo de encabezado debe incluir TODOS los encabezados para que sea compilable. Y no olvide usar declaraciones de reenvío en lugar de algunos encabezados.

En un archivo fuente:

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

En ese orden, no se perderá ninguno de sus archivos de encabezado que olvidó incluir sus propias bibliotecas.

Otros consejos

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

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

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

Para obtener más consejos excelentes, pruebe este libro: Diseño de software 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 ++.

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

El orden es de poca importancia, excepto si hace un gran uso de las 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 quiere, por supuesto).

Sobre esta declaración

  

los que requieren los encabezados posteriores deben ser anteriores

¡Un encabezado no debe depender de que se incluyan otros encabezados 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

EDIT

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

Por ejemplo, si uno de mis archivos usa una biblioteca que escribí, Qt, Boost y la biblioteca estándar, ordenaré las inclusiones 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 detectar dependencias faltantes en mis propios encabezados: supongamos, por ejemplo, que my_library.hpp usa std::copy, pero no incluye <algorithm>. Si lo incluyo después de foo.cpp en <=>, esta dependencia que falta pasará desapercibida. Por el contrario, con el orden que acabo de presentar, el compilador se quejará de que <=> no se ha declarado, lo que me permite corregir <=>.

En cada " biblioteca " grupo, 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 también es 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, cuantos más encabezados incluya, más código deberá volver a compilarse 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? ? ).

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

  

En dir / foo.cc, cuyo propósito principal es implementar o probar las cosas en dir2 / foo2.h, ordene sus inclusiones de la siguiente manera:

     
      
  • dir2 / foo2.h (ubicación preferida & # 8212; ver detalles a continuación).
  •   
  • archivos del sistema C.
  •   
  • archivos del sistema C ++.
  •   
  • Archivos .h de otras bibliotecas.
  •   
  • Los archivos .h de su proyecto.
  •   

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

El " cómo " no es obvio, pero el " what " es. Su objetivo es asegurarse de que el orden en el que incluya los archivos de encabezado nunca importe (y quiero decir & Quot; ¡NUNCA! & Quot;).

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

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

Es una cuestión de dependencia y depende en gran medida de lo que pongas en nuestros encabezados. Un hecho es que puede ser muy notorio sobre esto y minimizar para mantener sus inclusiones estrictas, pero eventualmente se encontrará con un escenario en el que querrá usar protectores de inclusión.

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

El problema no es tan aparente al principio, pero a medida que crece 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 incluye. Puedes intentarlo, pero solo puedes hacer mucho. Por lo tanto, sea diligente y piense en sus inclusiones. Pero seguramente tendrá dependencias cíclicas en algún momento y es por eso que necesita guardias de inclusión.

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

Intenta estructurar tu código para que pases punteros o referencias y declares hacia adelante donde puedas.

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

Generalmente los enumero como necesito.

La siguiente convención me pareció 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 & Quot; module.h & Quot; no tiene dependencias inesperadas.

Si está trabajando en un proyecto grande con tiempos de acceso lentos 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 se 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 protección, el compilador buscará y abrirá el archivo de encabezado, analizará todo el archivo para terminar #ifdef sacando todo el archivo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top