¿Cuál es la diferencia entre los archivos de encabezado y los archivos de origen en C ++?


Respuesta 1:

Las personas usan archivos de encabezado para organizar archivos en un paquete. Puede ver fácilmente lo que tiene un paquete leyendo los archivos de encabezado, donde las declaraciones están ordenadas (y generalmente comentadas). Puede hacerse una idea del funcionamiento sin tener que desplazarse por las líneas de código.

Los archivos de origen son generalmente donde se define el código real.

Este es un ejemplo genérico de C, por lo que no será preciso para la sintaxis de C ++ (estoy oxidado):

/ * foo.h * /
nulo func1 (int, int);

(Archivo separado)

/ * foo.c * /
#incluye "foo.h"
int main () {func1 (3,3); }

vacío func1 (int x, int y) {
    devuelve x + 2 * y * y;
}

¿Ves cómo pudiste usar func1 en la mayoría de foo.c sin tener que redefinir? Esto es otra cosa acerca de los archivos de encabezado: puede colocar las funciones más pequeñas debajo de todo (ya que main es lo más importante).

En C ++ tenemos mucha más funcionalidad: clases, espacios de nombres, etc. Todavía no está de más organizar los archivos de forma ordenada. Por ejemplo, podemos hacer declaraciones de clase en un encabezado y luego definir las funciones de clase en el código fuente.


Respuesta 2:

La respuesta simple es: los archivos de encabezado describen una interfaz; no contienen implementación de algoritmos. Para eso están los archivos de origen.

Pero esa es solo una explicación muy superficial. En realidad, puede implementar la funcionalidad en los archivos de encabezado. Llegaré a él, pero primero, ¿cuál es la diferencia práctica entre un "archivo de encabezado" y un "archivo fuente"?

La respuesta es: no hay absolutamente ninguna diferencia, aparte de la convencional. La directiva #include preprocesador le permite incorporar cualquier archivo en el lugar donde se encuentre. Pero (excepto en casos muy especiales), no desea incluir su código general (los archivos de origen). Lo que normalmente necesita es incorporar información de tipo y especificación de interfaz (declaraciones de función) para poder usarlas.

Si insertó su código, significaría que se multiplicaría en todos los archivos que incluyan el #include (nuevamente, el preprocesador solo copia ciegamente el contenido como si estuviera escrito en el punto de la directiva). Y eso probablemente causaría un comportamiento no deseado.

Ahora volvamos a la implementación de la funcionalidad en los archivos de "encabezado". Defines algún código en ellos:

  • Macros Una macro se expande en el punto de su uso. Una vez más, lo realiza el preprocesador y, de nuevo, es solo una reescritura directa del uso de macro definiendum por sus definiens (opcionalmente parametrizados). No se "llama" una macro; su uso solo se reescribe antes de la compilación. Funciones en línea. Estos podrían (y podrían no) funcionar de manera similar a las macros. Excepto que el compilador puede decidir definir una función verdadera (y generar su llamada) en lugar de incluir el contenido de la función. Se generaría una función común para cada #include (a menos que se considere implícitamente en línea, ver más abajo). Vea, el declarador en línea no es vinculante para el compilador; puede estar en línea, pero puede que no, es solo una "pista". De hecho, el estándar C ++ 17 cambia la semántica de inline a "múltiples definiciones permitidas". Así que ten cuidado; si, por ejemplo, crea una función en línea con datos estáticos dentro, puede terminar fácilmente teniendo múltiples instancias de esos datos estáticos (cada uno para una definición de la función). Probablemente no sea lo que querías ... Código de plantilla. Las plantillas son instanciadas. Cuando usa una plantilla para crear un tipo concreto, el compilador creará ese tipo localmente (como si lo definiera "manualmente" en el punto de su uso). Las funciones de plantilla se consideran implícitamente en línea (pero el compilador puede y a menudo decidirá no incluirlas en el tipo generado).

En términos generales, usted define sus tipos (públicos) y declara sus funciones en los archivos de encabezado. Usted define sus macros, plantillas y funciones en línea en ellos también. Usted define sus funciones en los archivos fuente y declara / define las funciones locales, no públicas, de tipos y estáticas allí también. Los encabezados son claves para acceder a la funcionalidad, las fuentes implementan la funcionalidad.

Los archivos de origen se compilan en archivos de "objeto". Estos incluirán todo el código generado a partir de la fuente y también contiene todo el código definido en los archivos de encabezado que incluye el archivo fuente # (recuerde que el código se inserta en el punto de uso de la directiva). Y finalmente, su programa (o biblioteca) consiste en estos archivos de objetos unidos entre sí.

Espero que esto ayude.


Respuesta 3:

Los archivos de origen son los archivos que contienen el código que se compila. La implementación de su algoritmo está contenida en un archivo fuente.

Los archivos de encabezado contienen código (generalmente definiciones de función o clase) que se copian en su archivo fuente mediante la directiva #include preprocesador. La gran ventaja de usar archivos de encabezado es la reutilización. Quiero decir, imagínense si tuviera que escribir el código para la definición de la clase de cadena cada vez que quisiera usarlo, cuando un simple #include funcionaría.


Respuesta 4:

Pones cosas en un archivo de encabezado que usarán OTROS archivos de origen (por otro me refiero al archivo de origen que no está implementando las cosas definidas en un encabezado)

Para ser pedante, los archivos de encabezado son una convención en C y C ++. Es posible que a algunos compiladores no les importe si le dice que compile un archivo con una extensión .h.

C tomó una ruta primitiva, pero razonablemente poderosa y flexible para implementar un preprocesador. Maneja #include y tal. El compilador solo ve el archivo después de que todas las inclusiones están ... incluidas. Un encabezado por convención nunca se compila. Solo está incluido (Nota que digo por CONVENCIÓN, hay excepciones por ahí). Así que simplemente colocas cosas en los encabezados que permiten que un archivo fuente sepa qué hay disponible en otros archivos fuente, como las funciones. O para tipos comunes. O prácticas macros. O ... bueno ... hay muchos usos.