В целом, не рекомендуется определять переменные в заголовочном файле - при условии, что указанный заголовочный файл будет включен в несколько исходных файлов.
Когда вы компилируете свой проект, препроцессор обрабатывает операторы "#include
", буквально помещая содержимое включенного заголовочного файла в файл, включающий его.
E.g.:
// foo.h
#ifndef FOO_H
#define FOO_H
typedef int myInt;
#endif
.
// main.cpp
#include "foo.h"
int main( int argc, char* argv[] )
{
return 0;
}
.
// preprocessor output
typedef int myInt;
int main( int argc, char* argv[] )
{
return 0;
}
Это упрощение - но достаточно хорошее для иллюстративных целей.
Так что же происходит в вашем примере?
arrayFile.hpp
включено classFile.hpp
, которое включено classFile.cpp
и mainfile.cpp
. Может быть полезно рассмотреть дерево включения:
arrayFile.hpp
|
classFile.hpp
/ \
classFile.cpp mainfile.cpp
Подумайте о том, что я сказал RE: заменив include
s включенным содержимым файла, и посмотрите, не согласны ли вы, когда я скажу, что classFile.cpp
и mainfile.cpp
оба заканчиваются на определение вашего arr
массива.
Что будет дальше, когда вы компилируете свой проект? Компилятор компилирует ваш исходный код - , в частности, вывод препроцессора - в объектные файлы. Например. предварительно обработанный classFile.cpp
становится classFile.o
, а предварительно обработанный mainfile.cpp
становится mainfile.o
.
Наконец, объектные файлы (или библиотеки, в которые они архивируются) связаны для формирования вашего исполняемого файла.
Когда компоновщик пытается связать classFile.o
и mainfile.o
, он обнаруживает, что оба имеют arr
, определенные в них. Таким образом, вы получаете множественное определение ошибка компоновщика - не ошибка компилятора .
Итак: если заголовочный файл включен - прямо или косвенно - несколькими исходными файлами, вы столкнетесь с ошибками компоновщика , если заголовочный файл определит переменные. Вот почему стандартная практика объявлять переменные в заголовочных файлах и определять их в одном исходном файле.
Надеюсь, это поможет.