2009-03-05 48 views
31

¿Qué orden deberían los encabezados declararse en un archivo de encabezado/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?Orden de encabezado C++

Respuesta

59

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 de origen:

  • de ficheros de inclusión correspondía
  • encabezados necesarios para el proyecto
  • bibliotecas 3 ª parte de encabezados
  • bibliotecas estándar cabeceras de
  • cabeceras de sistema

En ese para que no se pierda ninguno de ustedes r archivos de cabecera que olvidaron incluir bibliotecas por su cuenta.

+2

Creo que los "encabezados de proyecto necesarios" deben estar separados en dos elementos: - encabezados de proyecto de la misma lib; - encabezados de otras bibliotecas de proyectos (en orden donde la mayoría de los encabezados de libs de proyectos siguen a continuación que algunos encabezados de libs de proyectos especiales) – bayda

+2

Me gusta mucho su pedido. De esta forma, los encabezados no dependen de otros encabezados para incluir sus dependencias. – fmuecke

3

que utiliza para ordenar en orden alfabético (fácil de encontrar)

+0

Así es como lo hace Epic, en su documento de estilo Unreal Engine 4. –

0

Es una cosa dependencia y que depende en gran medida de lo que se pone en nuestras cabeceras. 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 que la aparente al principio, pero a medida que la complejidad de su software crece también lo hace su 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.

+1

¿No es esto lo mismo que llamar '#pragma una vez'? – Konrad

+1

Sí (es más o menos) lo mismo, pero #pragma una vez no es estándar. –

+0

Para el registro #pragma una vez es una extensión de Microsoft. Si estoy trabajando en un proyecto multiplataforma, lo uso así como también incluyo guardias porque #pragma una vez realmente impide el análisis del archivo. –

20

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 incluya.

Para obtener más consejos excelentes, pruebe este libro: Large-Scale C++ Software Design - 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++.

+0

Lo hago en mi unidad de pruebas en su lugar. – Ferruccio

+4

Una prueba más fácil de automatizar: solo compile (-c) cada archivo de encabezado (sí, g ++ -c blah.h) y asegúrese de que se compile. Puede tirar los archivos del objeto. –

+0

+1, hay mucho que no se dice en esa respuesta. ¡Un gran consejo! –

1

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 Google C++ Style Guide.

0

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

Intenta estructurar tu código para que apuntes los punteros o las referencias y reenviar declarar donde puedas.

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

Generalmente los enumero como lo necesito.

6

En archivos de encabezado, 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 pedido 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 desea, por supuesto).

En cuanto a esta declaración

los que son requeridos por las cabeceras posteriores debe ser anterior incluyéndose

Una cabecera no debe depender de otras cabeceras antes de que! Si requiere encabezados, solo los incluye. guardias de cabecera evitarán múltiples inclusión:

#ifndef FOO_HEADER_H 
#define FOO_HEADER_H 
... 
#endif 

EDITAR

Desde que escribí esta respuesta, he cambiado mi manera de ordenar la incluyen directivas 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 de los encabezados de las bibliotecas de terceros, seguidos por los encabezados estándar.

Por ejemplo, si uno de mi archivo utiliza una biblioteca que escribí, Qt, Boost y la biblioteca estándar, que ordenará la incluye como sigue:

//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 esto 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 incluyo 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 std::copy no ha sido declarado, lo que me permite corregir my_library.hpp.

En cada grupo de "biblioteca", trato de mantener las directivas include 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 When can I use a forward declaration?).

+0

+1 para incluir/guardias de encabezado. – polarise

-1

He encontrado la siguiente convención la más útil:

módulo.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 al disco lento, he visto este estilo se usa para disminuir los tiempos de construcció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 verbosa pero guarda en la búsqueda del 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á el archivo completo para terminar con el archivo completo.

2

El "cómo" no es obvio, pero el "qué" es. 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 se compilan al compilar archivos cpp (uno para cada archivo de encabezado) que solo incluyen uno de ellos.

5

Google C++ Style Guide, Names and Order of Includes:

En dir/foo.cc, cuyo principal objetivo es poner en práctica o probar la materia en directorio2/foo2.h, ordenar su incluye los siguientes:

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

sí, pero la guía de estilo GGL tiene algunas cosas desagradables :) –