#новичкам
В С/С++ существует интересная механика - разделение на объявление сущности и ее определение. У этого есть серьезные причины:
👉🏿 Ускорение компиляции: изменения в реализации не требуют перекомпиляции всех файлов, использующих объявление.
👉🏿 Сокрытие реализации: инкапсуляция, предоставление только интерфейса (в .hpp) и скрытие деталей в .cpp.
👉🏿 Разрешение циклических зависимостей и возможность ссылаться на типы до их полного определения.
👉🏿 Организация кода и разделение ответственности.
И если с функциями более менее понятно. Есть объявление в виде обозначения сигнатуры функции. И определение в виде полного предоставления тела функции:
void foo(int a); // declaration
void foo(int a) {
std::cout << a << std::endl; // definition
}
С переменными все немного сложнее. Но начнем с легкого:
int i = 0;
Это определение хоть глобальной, хоть локальной переменной
i и ее инициализация нулем. Все все понимают.Если думать в аналогии с функциями, то легко дойти до мысли что:
int i;
это объявление переменной.
Но это не так!
Это в любом случае определение!
Если вы встретите такую строчку вне функции, то это определение переменной и ее инициализация нулем. А внутри функции - определение без инициализации(значение будет мусорное). Определение переменной всегда связано с созданием объекта и выделением памяти под него.
Тогда как сказать компилятору, что я буду использовать переменную с каким-то именем и типом, но не хочу создавать объект а буду сслаться на определение в другом месте?
Ровно для этого и нужно ключевое слово extern.
extern int i; // declaration
int main() {
std::cout << i << std::endl;
}
int i = 42;
// OUTPUT
// 42
До мейна мы сказали, что будем ссылаться на переменную i, определение которой лежит в другом месте. И сразу после мейна предоставляем это определение. Компилятор все понял и в итоге мы получаем 42 на консоли, а не ноль.
В этом случае строчка
extern int i; является объявлением глобальной переменной i.Определение переменной может находиться хоть в другой единице трансляции. Просто тогда зависимости будут разрешаться на этапе линковки.
Для локальных переменных функций объявление не предусмотрено(оно и не нужно). Если попытаетесь сделать так:
int main() {
extern int i;
std::cout << i << std::endl;
}То вы опять объявите глобальную переменную
i.То есть чисто объявить вы можете только глобальную переменную (про полям класса речь не идет) и только с помощью
extern. Declare your intentions. Stay cool.
#cppcore