El hecho es que, en C ++, esto es algo más complicado que la organización del encabezado / fuente de C.
¿Qué ve el compilador?
El compilador ve un archivo fuente grande (.cpp) con sus encabezados incluidos correctamente. El archivo fuente es la unidad de compilación que se compilará en un archivo objeto.
Entonces, ¿por qué son necesarios los encabezados?
Porque una unidad de compilación podría necesitar información sobre una implementación en otra unidad de compilación. Entonces, uno puede escribir, por ejemplo, la implementación de una función en una fuente y escribir la declaración de esta función en otra fuente que necesite usarla.
En este caso, hay dos copias de la misma información. Que es el mal ...
La solución es compartir algunos detalles. Si bien la implementación debe permanecer en la fuente, la declaración de símbolos compartidos, como funciones, o la definición de estructuras, clases, enumeraciones, etc., podría necesitar ser compartida.
Los encabezados se utilizan para poner esos detalles compartidos.
Mover al encabezado las declaraciones de lo que se debe compartir entre múltiples fuentes
¿Nada mas?
En C ++, hay algunas otras cosas que se podrían poner en el encabezado porque también necesitan ser compartidas:
- código en línea
- plantillas
- constantes (generalmente las que desea usar dentro de los interruptores ...)
Mueva al encabezado TODO lo que necesita ser compartido, incluidas las implementaciones compartidas
¿Significa entonces que podría haber fuentes dentro de los encabezados?
Si. De hecho, hay muchas cosas diferentes que podrían estar dentro de un "encabezado" (es decir, compartidas entre fuentes).
- Declaraciones futuras
- declaraciones / definición de funciones / estructuras / clases / plantillas
- implementación de código en línea y con plantilla
Se vuelve complicado, y en algunos casos (dependencias circulares entre símbolos), imposible mantenerlo en un encabezado.
Los encabezados se pueden dividir en tres partes
Esto significa que, en un caso extremo, podría tener:
- un encabezado de declaración hacia adelante
- un encabezado de declaración / definición
- un encabezado de implementación
- una fuente de implementación
Imaginemos que tenemos un MyObject con plantilla. Nosotros podríamos tener:
// - - - - MyObject_forward.hpp - - - -
// This header is included by the code which need to know MyObject
// does exist, but nothing more.
template<typename T>
class MyObject ;
.
// - - - - MyObject_declaration.hpp - - - -
// This header is included by the code which need to know how
// MyObject is defined, but nothing more.
#include <MyObject_forward.hpp>
template<typename T>
class MyObject
{
public :
MyObject() ;
// Etc.
} ;
void doSomething() ;
.
// - - - - MyObject_implementation.hpp - - - -
// This header is included by the code which need to see
// the implementation of the methods/functions of MyObject,
// but nothing more.
#include <MyObject_declaration.hpp>
template<typename T>
MyObject<T>::MyObject()
{
doSomething() ;
}
// etc.
.
// - - - - MyObject_source.cpp - - - -
// This source will have implementation that does not need to
// be shared, which, for templated code, usually means nothing...
#include <MyObject_implementation.hpp>
void doSomething()
{
// etc.
} ;
// etc.
¡Guauu!
En la "vida real", suele ser menos complicado. La mayor parte del código tendrá solo una organización de fuente / encabezado simple, con algo de código en línea en la fuente.
Pero en otros casos (objetos con plantilla que se conocen entre sí), tenía que tener para cada objeto encabezados de declaración e implementación separados, con una fuente vacía que incluye esos encabezados solo para ayudarme a ver algunos errores de compilación.
Otra razón para dividir los encabezados en encabezados separados podría ser acelerar la compilación, limitando la cantidad de símbolos analizados a lo estrictamente necesario y evitando la recopilación innecesaria de una fuente que solo se preocupa por la declaración directa cuando cambia la implementación de un método en línea.
Conclusión
Debe hacer que la organización de su código sea lo más simple posible y lo más modular posible. Ponga tanto como sea posible en el archivo fuente. Solo exponga en los encabezados lo que debe compartirse.
Pero el día en que tenga dependencias circulares entre los objetos con plantilla, no se sorprenda si la organización de su código se vuelve algo más "interesante" que la organización simple de encabezado / fuente ...
^ _ ^