Eu já vi que existem vários paradigmas diferentes no C ++ sobre o que entra no arquivo de cabeçalho e o que o arquivo cpp. AFAIK, a maioria das pessoas, especialmente as que têm experiência em C, fazem:
foo.h
class foo {
private:
int mem;
int bar();
public:
foo();
foo(const foo&);
foo& operator=(foo);
~foo();
}
foo.cpp
#include foo.h
foo::bar() { return mem; }
foo::foo() { mem = 42; }
foo::foo(const foo& f) { mem = f.mem; }
foo::operator=(foo f) { mem = f.mem; }
foo::~foo() {}
int main(int argc, char *argv[]) { foo f; }
No entanto, meus professores geralmente ensinam C ++ para iniciantes como este:
foo.h
class foo {
private:
int mem;
int bar() { return mem; }
public:
foo() { mem = 42; }
foo(const foo& f) { mem = f.mem; }
foo& operator=(foo f) { mem = f.mem; }
~foo() {}
}
foo.cpp
#include foo.h
int main(int argc, char* argv[]) { foo f; }
// other global helper functions, DLL exports, and whatnot
Originalmente vindo de Java, também sempre segui esse segundo caminho por várias razões, como por exemplo, que só preciso alterar algo em um só lugar se os nomes da interface ou do método mudarem, pois gosto da indentação diferente das coisas nas classes quando veja a implementação deles e acho os nomes mais legíveis em foo
comparação com foo::foo
.
Quero coletar prós e contras de qualquer maneira. Talvez ainda haja outras maneiras?
Uma desvantagem do meu caminho é, obviamente, a necessidade de declarações futuras ocasionais.
fonte
foo.cpp
agora não tem nada a ver com suafoo
classe e deve ser deixado em branco (talvez,#include
para deixar seu sistema de compilação feliz).Respostas:
Embora a segunda versão seja mais fácil de escrever, ela mistura interface com implementação.
Os arquivos de origem que incluem arquivos de cabeçalho precisam ser recompilados toda vez que os arquivos de cabeçalho são alterados. Na primeira versão, você alteraria o arquivo de cabeçalho apenas se precisar alterar a interface. Na segunda versão, você alteraria o arquivo de cabeçalho se precisar alterar a interface ou a implementação.
Além disso, você não deve expor os detalhes da implementação , obterá recompilação desnecessária com a segunda versão.
fonte
Fiz isso pela segunda vez em 93-95. Demorei alguns minutos para recompilar um aplicativo pequeno com 5 a 10 funções / arquivos (no mesmo PC 486 .. e não, eu também não sabia sobre aulas, tinha apenas 14 a 15 anos e não havia internet ) .
Portanto, o que você ensina para iniciantes e o que usa profissionalmente são técnicas muito diferentes, especialmente em C ++.
Eu acho que a comparação entre C ++ e um carro de F1 é adequada. Você não coloca iniciantes em um carro de F1 (que nem liga, a menos que você pré-aqueça o motor a 80-95 graus Celsius).
Não ensine C ++ como o primeiro idioma. Você deve ter experiência suficiente para saber por que a opção 2 é pior do que a opção 1 em geral, saber um pouco o que significa compilação / vinculação estática e, portanto, entender por que o C ++ prefere da primeira maneira.
fonte
O segundo método é o que eu chamaria de classe totalmente embutida. Você está escrevendo uma definição de classe, mas todo o seu código usado apenas embutirá o código.
Sim, o compilador decide quando incorporar e quando não ... Nesse caso, você está ajudando o compilador a tomar uma decisão e, potencialmente, acabará gerando menos código e potencialmente mais rápido.
É provável que essa vantagem supere o fato de que, se você modificar a implementação de uma função, precisará reconstruir toda a fonte que a usa. Na natureza leve da classe, você não estará modificando a implementação. Se você adicionar um novo método, precisará modificar o cabeçalho de qualquer maneira.
À medida que sua classe fica mais complexa, mesmo adicionando um loop, o benefício de fazê-lo dessa maneira diminui.
Ainda tem suas vantagens, em particular:
A desvantagem de inlining se torna um problema quando isso significa que você precisa incluir detalhes de implementação em seu cabeçalho, ou seja, você precisa começar a incluir cabeçalhos extras.
Observe que os modelos são um caso especial, pois você praticamente precisa incluir os detalhes da implementação. Você pode ocultá-lo em outro arquivo, mas ele precisa estar lá. (Há uma exceção a essa regra com instanciações, mas em geral você alinha seus modelos).
fonte
Pode não ser significativo ou verdadeiro se o seu executável ficar maior, mas mais código nos arquivos de cabeçalho permite ao compilador mais chances de otimizar a velocidade.
Se você decidir decidir escrever uma biblioteca somente de cabeçalho , este tópico é apenas uma de suas preocupações.
fonte