Во-первых, чтобы ответить на ваш первый запрос:
Когда вы видите это в .h файле:
#ifndef FILE_H
#define FILE_H
/* ... Declarations etc here ... */
#endif
Это препроцессорная техника предотвращения многократного включения заголовочного файла, что может быть проблематичным по разным причинам. Во время компиляции вашего проекта каждый файл .cpp (обычно) компилируется. Проще говоря, это означает, что компилятор возьмет ваш файл .cpp , откроет все его файлы #included, объединит их все в один массивный текстовый файл, а затем выполнит синтаксический анализ и, наконец, преобразует его в некоторый промежуточный код, оптимизирует / выполняет другие. задач и, наконец, сгенерировать выходные данные сборки для целевой архитектуры. Из-за этого, если файл #includedнесколько раз под одним .cppфайл, компилятор добавит содержимое своего файла дважды, поэтому, если в этом файле есть определения, вы получите ошибку компилятора, сообщающую, что вы переопределили переменную. Когда файл обрабатывается на этапе препроцессора в процессе компиляции, при первом достижении его содержимого первые две строки проверят, был ли FILE_Hон определен для препроцессора. Если нет, он определит FILE_Hи продолжит обработку кода между ним и #endifдирективой. В следующий раз, когда препроцессор увидит содержимое этого файла, проверка FILE_Hбудет ложной, поэтому он будет сразу же сканировать до #endifи продолжать после него. Это предотвращает ошибки переопределения.
И для решения вашей второй проблемы:
В программировании на C ++ в качестве общей практики мы разделяем разработку на два типа файлов. Один с расширением .h, и мы называем это «заголовочный файл». Обычно они предоставляют объявление функций, классов, структур, глобальных переменных, typedefs, макросов и определений предварительной обработки и т. Д. По сути, они просто предоставляют вам информацию о вашем коде. Затем у нас есть расширение .cpp, которое мы называем «файл кода». Это обеспечит определения для этих функций, членов класса, любых элементов структуры, которым нужны определения, глобальные переменные и т. Д. Таким образом, файл .h объявляет код, а файл .cpp реализует это объявление. По этой причине мы обычно во время компиляции компилируем каждый .cppфайл в объект и затем связать эти объекты (потому что вы почти никогда не видите, чтобы один файл .cpp включал другой файл .cpp ).
Как эти внешние проблемы решаются - работа для компоновщика. Когда ваш компилятор обрабатывает main.cpp , он получает объявления для кода в class.cpp , включая class.h . Нужно только знать, как выглядят эти функции или переменные (что дает вам объявление). Поэтому он компилирует ваш файл main.cpp в некоторый объектный файл (назовите его main.obj ). Аналогично, class.cpp компилируется в class.objфайл. Чтобы создать конечный исполняемый файл, вызывается компоновщик, который связывает эти два объектных файла вместе. Для любых неразрешенных внешних переменных или функций компилятор поместит заглушку, где происходит доступ. Затем компоновщик возьмет эту заглушку и найдет код или переменную в другом указанном объектном файле, и, если он найден, он объединит код из двух объектных файлов в выходной файл и заменит заглушку с окончательным расположением функции или переменная. Таким образом, ваш код в main.cpp может вызывать функции и использовать переменные в class.cpp ЕСЛИ И ТОЛЬКО ЕСЛИ ОНИ ОБЪЯВЛЕНЫ в class.h .
Я надеюсь, что это было полезно.