Файлы заголовков C ++, разделение кода
Я новичок в C ++, и у меня было несколько общих вопросов о разделении кода. В настоящее время я создал небольшое приложение, все в одном файле. То, что я хочу сделать сейчас, это преобразовать это в отдельные файлы, чтобы они содержали аналогичный код или еще много чего. Мой настоящий вопрос прямо сейчас, как я могу узнать, как отделять вещи? Каков невидимый запас, который должен разделять код?
Кроме того, в чем смысл заголовочных файлов? Должен ли он пересылать методы и classы объявлений, чтобы я мог использовать их в своем коде, прежде чем они будут включены компоновщиком во время компиляции?
Любое понимание методов или передовой практики было бы здорово, спасибо!
- Почему большинство полей (участников classа) в учебнике Android начинаются с `m`?
- андроид динамически меняет стиль во время выполнения
- Использование библиотеки FFMPEG с iPhone SDK для кодирования видео
- Как изменить кодировку по умолчанию в NetBeans 8.0
- Код C ++ в файлах заголовков
- Пусть объект JSON принимает байты или позволяет выводить строки вывода
- Кодировать NSString для XML / HTML
- #ifdef vs #if - что лучше / безопаснее как способ включения / отключения компиляции определенных разделов кода?
- Соглашения Java: использовать getters / setters внутри classа?
- Что такое кодировка символов и почему я должен ее беспокоить?
- URL-код, кодирующий символ пробела: + или% 20?
- Какую кодировку использует Microsoft Excel при сохранении файлов?
- Зачем использовать префиксы для переменных-членов в classах C ++
Во-первых, вы не должны помещать что-либо в заголовки, которые не нужны, чтобы быть видимыми каким-либо другим файлом, отличным от того, который ему нужен. Тогда давайте определим то, что нам нужно ниже.
Блок переводов
Модуль перевода – это текущий код, который скомпилирован, и весь код, включенный в него, прямо или косвенно. Один модуль перевода переводится в один файл .o / .obj.
программа
Это все ваши файлы .o / .obj, связанные друг с другом в один двоичный файл, который может быть выполнен для формирования процесса.
Каковы основные моменты наличия разных единиц перевода?
- Уменьшите зависимости, чтобы при изменении одного метода одного classа вам не нужно перекомпилировать весь код вашей программы, но только затронутую единицу перевода.
- Сократите возможные конфликты имен, если у вас есть локальные имена единиц перевода, которые не отображаются другой единицей перевода при их объединении.
Теперь, как вы можете разделить свой код на разные единицы перевода? Ответ заключается в том, что нет «так вы это делаете!», Но вы должны рассматривать его в каждом конкретном случае. Часто бывает ясно, что у вас разные classы, которые можно и нужно поместить в разные единицы перевода:
foo.hpp:
/* Only declaration of class foo we define below. Note that a declaration * is not a definition. But a definition is always also a declaration */ class foo; /* definition of a class foo. the same class definition can appear in multiple translation units provided that each definition is the same basicially, but only once per translation unit. This too is called the "One Definition Rule" (ODR). */ class foo { /* declaration of a member function doit */ void doit(); /* definition of an data-member age */ int age; };
Объявите некоторые свободные функции и объекты:
/* if you have translation unit non-local (with so-called extern linkage) names, you declare them here, so other translation units can include your file "foo.hpp" and use them. */ void getTheAnswer(); /* to avoid that the following is a definition of a object, you put "extern" in front of it. */ extern int answerCheat;
foo.cpp:
/* include the header of it */ #include "foo.hpp" /* definition of the member function doit */ void foo::doit() { /* ... */ } /* definition of a translation unit local name. preferred way in c++. */ namespace { void help() { /* ... */ } } void getTheAnswer() { /* let's call our helper function */ help(); /* ... */ } /* define answerCheat. non-const objects are translation unit nonlocal by default */ int answerCheat = 42;
bar.hpp:
/* so, this is the same as above, just with other classes/files... */ class bar { public: bar(); /* constructor */ };
bar.cpp:
/* we need the foo.hpp file, which declares getTheAnswer() */ #include "foo.hpp" #include "bar.hpp" bar::bar() { /* make use of getTheAnswer() */ getTheAnswer(); }
Обратите внимание, что имена в анонимном пространстве имен (как указано выше) не конфликтуют, поскольку они кажутся явной единицей перевода. на самом деле это не так, у них просто уникальные имена, чтобы они не столкнулись. если вы действительно хотите (есть мало причин) для перевода единиц локальных имен (например, из-за совместимости с c, поэтому код C может вызвать вашу функцию), вы можете сделать это следующим образом:
static void help() { /* .... */ }
В ODR также говорится, что вы не можете иметь более одного определения любого объекта или не встроенной функции в одной программе (classы – это типы, а не объекты, поэтому к ним они не применяются). Таким образом, вы должны следить за тем, чтобы не помещать не-встроенные функции в заголовки или не помещать объекты типа «int foo;» в заголовках. Это вызовет ошибки компоновщика тогда, когда компоновщик попытается связать единицы перевода, включая эти заголовки.
Надеюсь, я немного помогу. Теперь это был длинный ответ, где-то есть ошибки. Я знаю, что единица перевода строго определяется другим способом (выход препроцессора). Но я думаю, что это не добавило бы большой ценности, чтобы включить это в вышеупомянутое, и это смутит вопрос. Пожалуйста, не стесняйтесь, если найдете реальные ошибки 🙂
Методы программирования: C / CPP.
Организация файлов кода на C и C ++
Решение о том, как разделить ваш код на разные classы / функции, является одной из основных задач программирования. Существует множество различных рекомендаций относительно того, как это сделать, и я бы рекомендовал прочитать некоторые руководства по C ++ и объектно-ориентированному дизайну, чтобы вы начали.
Некоторые основные рекомендации будут
- Соедините вещи, которые используются вместе
- Создание classов для объектов домена (например, файлов, коллекций и т. Д.)
Заголовочные файлы позволяют объявлять class или функцию, а затем использовать ее в нескольких разных исходных файлах. Например, если вы объявляете class в файле заголовка
// Ah class A { public: int fn(); };
Затем вы можете использовать этот class в нескольких исходных файлах:
// A.cpp #include "Ah" int A::fn() {/* implementation of fn */} //B.cpp #include "Ah" void OtherFunction() { A a; a.fn(); }
Таким образом, заголовочные файлы позволяют отделить декларацию от реализации. Если вы должны поместить все (объявление и реализацию) в исходный файл (например, A.cpp), попробуйте включить его во второй файл, например
// B.cpp #include "A.cpp" //DON'T do this!
Затем вы можете скомпилировать B.cpp, но когда вы попытаетесь связать свою программу, компоновщик будет жаловаться, что у вас есть многократно определенные объекты – это потому, что у вас есть несколько копий реализации A.
Предложение: 1. У вас есть готовый дизайн для вашего приложения. 2. На основе дизайна создайте необходимые объекты, которые взаимодействуют друг с другом. 3. Рефакторинг или полностью изменить существующий код в соответствии с недавно созданным дизайном.
Файлы заголовков предоставляют интерфейс для других classов, которые могут использовать его функциональные возможности.