Я начал писать простой интерпретатор в C ++ со структурой классов, которую я опишу ниже, но я бросил и переписал эту вещь в Java, потому что заголовки доставляли мне трудные времена. Вот основная структура, которая явно не разрешена в C ++:
main.cpp содержит основную функцию и включает в себя заголовок для класса, который мы можем вызвать printer.h (чей единственный метод void реализован в printer.cpp). Теперь представьте два других класса, которые идентичны. Оба хотят позвонить Printer::write_something();
так я включил printer.h в каждом. Итак, вот мой первый вопрос: почему я могу #include <iostream>
миллион раз, даже один за другим, но я могу только включить мой заголовок один раз? (Ну, я думаю, что я мог бы сделать то же самое с моим, если он находится в том же файле. Но я могу ошибаться.) Я понимаю разницу между объявлением и реализацией / определением, но этот код дает мне Ошибка переопределения класса. Я не понимаю почему. И вот что поражает меня (и, вероятно, показывает, почему я ничего не понимаю): я не могу просто включить printer.h на вершине main.cpp и использовать класс из моих двух других классов. Я знаю, что могу включить printer.h в один из двух классов (заголовков) без проблем, но я не понимаю, почему это отличается от простого включения до того, как я включил класс в main.cpp (как это делает мне класс не найдена ошибка).
Когда я сыт по горло, я думал о переходе на C, так как используемый мной ООП в любом случае был довольно вынужденным, но я столкнулся бы с той же проблемой, если не записал все в один файл. Очень неприятно знать C ++, но не могу правильно его использовать из-за проблем с компиляцией.
Я был бы очень признателен, если бы вы могли прояснить это для меня. Спасибо!
Почему я могу включить миллион раз, даже один за другим, но мой заголовок я могу включить только один раз?
Это, вероятно, потому что ваш заголовок не имеет включить охрану.
// printer.h file
#ifndef PRINTER_H_
#define PRINTER_H_
// printer.h code goes here
#endif
Обратите внимание, что рекомендуется выбирать более длинные имена для определений include guard, чтобы минимизировать вероятность того, что два разных заголовка могут иметь один и тот же заголовок.
Большинство заголовочных файлов должны быть упакованы в include guard:
#ifndef MY_UNIQUE_INCLUDE_NAME_H
#define MY_UNIQUE_INCLUDE_NAME_H
// All content here.
#endif
Таким образом, компилятор будет видеть содержимое заголовка только один раз на единицу перевода.
Компиляция C / C ++ делится на блоки компиляции / трансляции для генерации объектных файлов. (.o, .obj)
смотрите здесь определение единицы перевода
Директива #include в файле C / C ++ приводит к прямому эквиваленту простой рекурсивной копирования-вставки в том же файле. Вы можете попробовать это в качестве эксперимента.
Таким образом, если один и тот же модуль перевода включает в себя один и тот же заголовок дважды, компилятор видит, что некоторые сущности определяются несколько раз, как это было бы, если бы вы записали их в один и тот же файл. Вывод ошибки будет точно таким же.
В языке нет встроенной защиты, которая мешает вам делать несколько включений, поэтому вам приходится прибегать к написанию шаблона include guard или конкретного шаблона #pragma для каждого заголовка C / C ++.