Por que seu código não compila: o mistério do extern em C++
\n\nVocê já escreveu um programa organizado em C++, dividiu-o em vários arquivos, compilou — e recebeu uma parede de erros como multiple definition of 'myVariable' ou undefined reference to 'myVariable'? Familiar? Se sim — você não está sozinho. A pergunta "How do I use extern to share variables between source files?" está entre as mais populares no Stack Overflow, com dezenas de milhares de visualizações.
O problema é simples: quando o projeto cresce, manter todo o código em um único main.cpp é impossível. Mas como fazer para que uma variável, declarada em config.cpp, seja visível em game.cpp e render.cpp? A intuição sugere: "Apenas declare-a globalmente!" — mas o compilador pensa diferente. Para ajudar, surge a pequena, mas poderosa palavra-chave extern. Vamos entender como ela funciona na prática, para que você nunca mais se confunda com a vinculação.
O que é extern e para que serve?
\n\nEm C++, cada nome (variável, função, classe) deve ser declarado (declared) antes do uso e definido (defined) exatamente uma vez. A definição é o que aloca memória. A declaração é apenas uma promessa ao compilador: "Não se preocupe, a definição está em algum outro arquivo, vou mostrar o tipo e o nome".
\n\nA palavra-chave extern é exatamente essa promessa. Ela diz ao compilador: "Esta variável está definida em outro lugar, não aloque memória para ela aqui — apenas me dê acesso a ela".
Sem o extern, cada tentativa de declarar uma variável global em dois arquivos .cpp resultará em um erro do vinculador: duas definições — duas áreas de memória — conflito.
A regra dos três arquivos: como organizar o código
\n\nO padrão comum para compartilhar variáveis entre arquivos em C++ é o seguinte:
\n\n- \n
- Arquivo de definição (*.cpp) — contém uma definição da variável. \n
- Arquivo de cabeçalho (*.h) — contém a declaração
externda variável. \n - Qualquer outro arquivo .cpp — inclui o cabeçalho e usa a variável. \n
Exemplo 1: Compartilhando um número inteiro
\n\nImagine que estamos escrevendo um jogo e queremos armazenar a pontuação global em um arquivo separado. Veja como fazer isso corretamente.
\n\nArquivo: globals.cpp — aqui vive a variável real:
// globals.cpp\n#include "globals.h"\n\nint gameScore = 0; // Definição: memória é alocada aqui\n\nArquivo: globals.h — declaração para todos os outros:
// globals.h\n#ifndef GLOBALS_H\n#define GLOBALS_H\n\nextern int gameScore; // Declaração: "procure a definição em outro .cpp"\n\n#endif // GLOBALS_H\n\nArquivo: main.cpp — usamos a variável:
// main.cpp\n#include <iostream>\n#include "globals.h"\n\nvoid updateScore(int points) {\n gameScore += points; // Funciona! extern deu acesso\n}\n\nint main() {\n gameScore = 100;\n updateScore(50);\n std::cout << "Score: " << gameScore << std::endl; // Exibirá 150\n return 0;\n}\n\nArquivo: display.cpp — outro arquivo que precisa de acesso:
// display.cpp\n#include <iostream>\n#include "globals.h"\n\nvoid showScore() {\n std::cout << "Current score: " << gameScore << std::endl;\n}\n\nObserve: gameScore é definido exatamente uma vez — em globals.cpp. Em todos os outros lugares, usamos extern int gameScore (através do cabeçalho).
Erro comum nº1: definição no arquivo de cabeçalho
\n\nIniciantes frequentemente escrevem assim no arquivo .h:
// RUIM: ba