O que está por trás das palavras "declaração" e "definição"?
Imagine que você está construindo um enorme arranha-céu. Você tem um projeto (declaração) e uma coluna de concreto real (definição). Sem o projeto, você não sabe como a coluna deve ser. Sem a coluna, o edifício desaba. Em C++ é exatamente a mesma história, mas com uma nuance importante: se você errar, não será o edifício que desabará, mas sim o seu programa — com um erro de compilação ou de linkagem.
A pergunta "What is the difference between a definition and a declaration?" já é há muitos anos uma das mais populares no Stack Overflow. E não é à toa. Até desenvolvedores experientes às vezes se confundem, especialmente quando se trata de extern, static ou templates. Em 2025, com o aumento da complexidade dos projetos e o uso dos módulos do C++20, entender essa diferença se torna uma habilidade crítica.
Neste artigo, não vamos apenas dar uma definição seca. Vamos analisar código vivo, mostrar as "armadilhas" em que os iniciantes caem e dar as melhores práticas que economizarão horas de depuração.
Declaration é uma promessa ao compilador
Declaração (declaration) é uma forma de dizer ao compilador: "Ei, escuta, essa coisa existe! Ela tem um nome e um tipo, mas onde ela está e como ela se parece — por enquanto é segredo".
Em palavras simples: a declaração introduz um nome no programa. Ela não aloca memória, não cria um objeto, não escreve o código de uma função. Ela apenas diz ao compilador: "Confie em mim, isso existe, use isso".
Veja como é uma declaração pura de função em C++:
// Declaração (declaration) de funçãoint calculateSum(int a, int b);
// Declaração de variável externaextern int globalCounter;Observe a palavra-chave extern para a variável. Sem ela, isso seria uma definição. Para funções, a palavra-chave não é necessária — se após a assinatura houver um ponto e vírgula, é uma declaração.
Para que servem as declarações?
- Forward declaration (declaração antecipada). Permite usar uma função antes que o compilador veja seu corpo. Exemplo clássico: duas classes que se referenciam mutuamente.
- Separação em .h e .cpp. Em arquivos de cabeçalho, escrevemos declarações; em arquivos de implementação, definições. Esta é a base da modularidade.
- Aceleração da compilação. O compilador não precisa analisar corpos de funções enormes a cada vez — apenas as assinaturas são suficientes.
Definition é a realidade
Definição (definition) é quando o compilador finalmente aloca memória ou gera código. É a realização da promessa.
Para uma função, a definição é o corpo da função. Para uma variável, é a alocação de memória. Para uma classe, é a descrição completa de todos os seus membros.
// Definição (definition) de funçãoint calculateSum(int a, int b) { return a + b;}
// Definição de variávelint globalCounter = 0; // Sem extern — isso é uma definição!
// Definição de classeclass MyClass {public: void doSomething() {} // Definição de método dentro da classe};A Regra de Uma Definição (ODR — One Definition Rule)
Esta é a regra mais importante que você deve lembrar. A ODR afirma: em todo o programa, só pode haver uma definição de cada entidade (função, variável, classe).
Mas pode haver quantas declarações você quiser! É por isso que em arquivos de cabeçalho escrevemos declarações, e em .cpp, a definição única. A violação da ODR leva a um erro de linkagem (linker error) — o mais desagradável, porque ocorre após a compilação.
Em 2025, com a ampla adoção do C++20 e dos módulos, a ODR se tornou mais fácil de cumprir. Mas o modelo clássico com arquivos de cabeçalho não desapareceu, e é necessário entendê-lo.