O fato é que, em C ++, isso é um pouco mais complicado do que a organização de cabeçalho / origem C.
O que o compilador vê?
O compilador vê um grande arquivo de origem (.cpp) com seus cabeçalhos incluídos corretamente. O arquivo de origem é a unidade de compilação que será compilada em um arquivo de objeto.
Então, por que os cabeçalhos são necessários?
Porque uma unidade de compilação pode precisar de informações sobre uma implementação em outra unidade de compilação. Assim, pode-se escrever, por exemplo, a implementação de uma função em uma fonte, e escrever a declaração dessa função em outra fonte que precise usá-la.
Nesse caso, existem duas cópias das mesmas informações. O que é mal ...
A solução é compartilhar alguns detalhes. Embora a implementação deva permanecer na Fonte, a declaração de símbolos compartilhados, como funções, ou definição de estruturas, classes, enums, etc., pode precisar ser compartilhada.
Os cabeçalhos são usados para colocar esses detalhes compartilhados.
Mova para o cabeçalho as declarações do que precisa ser compartilhado entre várias fontes
Nada mais?
Em C ++, existem algumas outras coisas que podem ser colocadas no cabeçalho porque também precisam ser compartilhadas:
- código embutido
- modelos
- constantes (geralmente aquelas que você deseja usar dentro dos interruptores ...)
Mova para o cabeçalho TUDO o que precisa ser compartilhado, incluindo implementações compartilhadas
Isso significa que pode haver fontes dentro dos cabeçalhos?
Sim. Na verdade, existem muitas coisas diferentes que podem estar dentro de um "cabeçalho" (ou seja, compartilhado entre as fontes).
- Declarações de encaminhamento
- declarações / definição de funções / estruturas / classes / modelos
- implementação de código embutido e modelo
Torna-se complicado e, em alguns casos (dependências circulares entre símbolos), impossível mantê-lo em um cabeçalho.
Os cabeçalhos podem ser divididos em três partes
Isso significa que, em um caso extremo, você poderia ter:
- um cabeçalho de declaração de encaminhamento
- um cabeçalho de declaração / definição
- um cabeçalho de implementação
- uma fonte de implementação
Vamos imaginar que temos um MyObject modelado. Poderíamos ter:
// - - - - 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.
Uau!
Na "vida real", geralmente é menos complicado. A maior parte do código terá apenas um cabeçalho / organização de origem simples, com algum código embutido no código-fonte.
Mas em outros casos (objetos modelados se conhecendo), tive que ter para cada objeto uma declaração separada e cabeçalhos de implementação, com uma fonte vazia incluindo esses cabeçalhos apenas para me ajudar a ver alguns erros de compilação.
Outra razão para dividir cabeçalhos em cabeçalhos separados pode ser acelerar a compilação, limitando a quantidade de símbolos analisados ao estritamente necessário e evitando recompilação desnecessária de uma fonte que se preocupa apenas com a declaração direta quando uma implementação de método inline é alterada.
Conclusão
Você deve tornar sua organização de código o mais simples possível e o mais modular possível. Coloque o máximo possível no arquivo de origem. Exponha apenas nos cabeçalhos o que precisa ser compartilhado.
Mas no dia em que você tiver dependências circulares entre objetos modelados, não se surpreenda se sua organização de código se tornar um pouco mais "interessante" que a organização de cabeçalho / fonte simples ...
^ _ ^