Для чего нужны Header файлы в С++? Почему нельзя писать без них?
Весь гугл перерыл, не могу понять. И википедию перечитал и вообще все что угодно перечитал. Правда не понимаю. Что мешает подключать просто .cpp файлы? Ну подключил ты его два раза, ну пусть компилятор только один раз подключает и все, раз он один черт все в один как бы файл склеивает, значит первое подключение будет выше остальных и будет видно им внизу. Пусть смотрит время изменения и перекомпилирует только изменившееся. Пусть автоматически генерирует и прикрепляет header файлы с описанием интерфейсов к откомпилированному бинарнику и т.п. Иными словами, почему рутиная работа по генерации хедер файлов, не автоматизирована и возложена на разработчика? Ведь компилятор рядом с откомпилированным бинарником может легко сам сгенерировать файл описания интерфейсов (который он получил, сканируя cpp файл). Можете привести ситуацию, в которой бы возникали ПРОБЛЕМЫ без использования хедер файлов? Это будет самое лучшее обьяснение.
Отслеживать
28.5k 12 12 золотых знаков 58 58 серебряных знаков 118 118 бронзовых знаков
задан 30 янв 2017 в 5:03
Maxmaxmaximus Maxmaxmaximus
933 2 2 золотых знака 9 9 серебряных знаков 19 19 бронзовых знаков
Комментарии не предназначены для расширенной дискуссии; разговор перемещён в чат.
5 фев 2017 в 9:57
Наверно уже сказали, но на всякий случай: Потому что можно писать без .h и можно просто включать .cpp Просто ты не понимаешь разницу между двумя подходами и не понимаешь поэтому, зачем это нужно — использовать заголовочные файлы.
9 янв 2020 в 7:01
6 ответов 6
Сортировка: Сброс на вариант по умолчанию
Проблема лежит в области обратной совместимости.
Посмотрите, любой новый язык программирования — да даже Паскаль, не говоря уже о Java или C# — не нуждаются в заголовочных файлах. Без сомнения, C++ тоже мог бы обойтись без них. В чём же дело?
Перенесёмся на полвека назад, в 1972 год. Представим себе компилятор языка C.
Допустим, мы хотим написать дизайн компилятора. Мы не можем скомпилировать всю программу за раз, у нас на это просто не хватит памяти. Компьютеры тогда были маленькими и медленными. Мы хотим компилировать программу по кусочкам, по нескольку функций за раз.
У нас сразу же возникает проблема: как скомпилировать функцию f , которая ссылается на другую функцию g ? Нам нужно отдельное описание других функций. Мы могли бы, конечно, прочитать все исходные файлы, для начала выяснить, какие функции у нас есть, и затем прочитать их второй раз и скомпилировать один за одним. Но это было слишком сложно и медленно, нужно было парсить определения функций дважды, и один раз выбрасывать результат! Это недопустимый расход процессорного времени! Плюс если держать в памяти определения всех функций, может снова-таки не хватить памяти.
На кого Деннис решил возложить сложную проблему отделения описания функции от её реализации, и подключения только нужных описаний при компиляции данной функции? На нас, программистов. Он решил, что мы должны сами помочь компилятору и скопипастить определения функций в отдельный файл, и сами указать компилятору, какие файлы с определениями нужны. (То есть первый шаг компиляции возлагается на нас.)
Это радикально упростило компилятор, но привело в свою очередь к проблемам. Что будет, если мы забыли подключить нужный заголовочный файл? Ответ: ошибка компиляции. Что будет, если смысл текста заголовочного файла меняется в зависимости от какого-нибудь макроса? Ответ: компилятор «тупой», и не пытается детектировать эту проблему, он перекладывает ответственность на нас.
На момент разработки языка это было правильное решение. Компилятор оказался практичным, быстрым, и программисты были не прочь помочь компиляции. Ну и если кто допускал ошибку, сам был виноват.
Перемотаем стрелки часов в 1983 год. Бьярн создаёт C++. Он решил взлететь на волне популярности языка C, и перенял модель компиляции C с отдельными translation unit’ами и связанными с этим проблемами прямо из C. Впрочем, первые версии C++ были просто препроцесоором языка C! Поэтому проблемы раздельной компиляции перекочевали из C в C++. Хуже того, добавились новые проблемы. Например, шаблоны классов выглядят как классы, но не генерируют объектного кода сами по себе, поэтому для них приходится идти на ухищрения и обходить недостатки системы раздельной компиляции (например, включением реализации в header и трюками компоновщика).
А дальше вступила в игру обратная совместимость. Сейчас, в 2017 году, есть так много кода, написанного в стиле «с заголовками», и так много кода исходит из различных тонкостей, связанных с этим, что менять парадигму уже поздно, поезд практически уехал.
Впрочем, существует проект модульной системы в C++, который должен помочь программистам избавиться от наследства полувековой давности. Он ещё не реализован, и в нём есть сложности уровня дизайна (например, в header’е был определён макрос, будет ли он виден, если мы перейдём от header’ов к модулям?) Надеюсь, в будущем разработчики языка таки смогут побороть проблему обратной совместимости.
Заголовочные файлы и файлы реализации
Все примеры, которые я использовал до этого, использовали только один файл, который компилировался через g++ . Несмотря на то, что большие программы можно написать в одном файле и скомпилировать его, такие программы редко бывают удобны для последующей работы. Код, написанный в одном многометровом файле запутывает и усложняет т.н. «рефакторинг».
Существуют помимо файлов исходников (или реализации), стандартно имеющие расширение .cpp , файлы, называемые заголовочными; они имеют расширение .h . Это позволяет разбить программу на фрагменты, логически и функционально связанные; размещать их в разных папках, которые объединяют логически несколько файлов в один пакет и т.д.
С заголовными файлами мы уже встречались, когда подключали, например, библиотеки для работы со строками следующим образом: #include . Напомню, что препроцессорная директива #include имеет 2 способа указания на внешние заголовные файлы: с помощью треугольных скобок (<>) и с помощью кавычек («»). Принципиальное различие состоит в том, что при указании <> компилятор будет пытаться искать заголовочные файлы в библиотеках, которые указаны в ОС как источники библиотек C++. При разработке собственных файлов необходимо использовать кавычки; они указывают компилятору, что заголовочный файл нужно искать относительно той директории, в которой находится компилируем исходный файл.
Возьмём последний пример из статьи про классы.
#include #include using namespace std; class Person < string lastname; string firstname; string middlename; public: Person(string lastname, string firstname, string middlename) : lastname(lastname), firstname(firstname), middlename(middlename) < cout friend ostream& operator; ostream& operator<<(ostream& os, Person &p) < os int main(int argc, char *argv[])
Вынесем класс в заголвочный файл, у нас получится следующее:
#include using namespace std; class Person < string lastname; string firstname; string middlename; public: Person(string lastname, string firstname, string middlename) : lastname(lastname), firstname(firstname), middlename(middlename) < cout friend ostream& operator<< (ostream &out, Person &p); >; ostream& operator<<(ostream& os, Person &p)
#include #include «person.h» int main(int argc, char const *argv[])
Собираем проект g++ main.cpp и получим точно такую же программу, как если бы сборка происходила из одного и того же файла. Это всё из-за того, что препроцессорная директива #include ищет нужные нам заголовочные файлы и включает их в тело программы. Таким образом нам удалось вынести целую сущность в отдельный файл! Теперь же необходимо избавиться от реализации в заголовчном файле. Это мотивировано тем, что некоторые программы могут быть исопльзованы сторонними людьми, поэтому они должны подключать заголовчный файл, наподобие того, как подключается файл со строками, а вот реализация для посторонних должна быть скрыта. Такие файлы комплириуются в статические или динамические библиотеки (последние знакомы всем жителями ОС Виндоус как .dll), но объяснение этих нюансов выходит за рамки этой статьи.
Выносим реализацию в отдельный файл и получаем проект из 3-х файлов (main.cpp не изменяется):
#include #include using namespace std; #ifndef PERSON_H #define PERSON_H class Person < string lastname; string firstname; string middlename; public: Person(string lastname, string firstname, string middlename); friend ostream& operator; #endif
#include #include #include "person.h" using namespace std; Person::Person(string lastname, string firstname, string middlename) : lastname(lastname), firstname(firstname), middlename(middlename) < cout ostream& operator
При реализации класса нам обязательно указывать название функции так: [Возвращаемое значеие] [Имя класса]::[Имя функции и аргументы] .
#ifndef PERSON_H , #define PERSON_H и #endif нужны для того, чтобы заголовончый файл при компиляции был включён в тело программы только 1 раз. Эти директивы прочитываются следующим образом: если не определён [название], тогда определить [название] и закончить проверку. Без этих директив, компилятор попытается подключить один и тот же заголовочный файл столько раз, сколько файлов реализаций его подключают; в нашем случае, это будет 2 раза: из файла main.cpp и файла person.cpp.
Для того, чтобы программа скомпилировалась, g++ нужно передавать в качестве аргументов оба файла реализации: g++ main.cpp person.cpp . Кстати, на этом этапе вы можете попытаться создать библиотеку person, скомпилированную в объектный файл. Поступим следующим образом:
g++ -c person.cpp g++ main.cpp person.o
Вы можете передать другому человеку только скомпилированный файл person.o и заголовочный файл person.h, и он сможет написать main.cpp и собрать программу (при условии, что у вас один и тот же компилятор)! Встаёт вопрос, как обеспечить сборку проекта из тысячи файлов? Не перечислять же их в аргументах, в самом деле. Для этих целей используются системы автоматической сборки, одной из которых является способ сборки с makefile. Прочитайте статью Makefile для самых маленьких, чтобы научится это делать.
2.10 – Заголовочные файлы
По мере того, как программы становятся больше (и используют больше файлов), становится всё более утомительным давать предварительные объявления каждой функции, которую вы хотите использовать, и которая определена в другом файле. Было бы неплохо, если бы вы могли поместить все свои предварительные объявления в одно место, а затем импортировать их, когда они вам понадобятся?
Исходные файлы кода C++ (с расширением .cpp ) – это не единственные файлы, которые обычно встречаются в программах на C++. Другой тип файлов – это заголовочный файл (иногда просто заголовок). Заголовочные файлы обычно имеют расширение .h , но иногда вы можете встретить их с расширением .hpp или вообще без расширения. Основная цель заголовочного файла – распространять объявления в исходные файлы кода.
Ключевой момент
Заголовочные файлы позволяют нам размещать объявления в одном месте, а затем импортировать их туда, где они нам нужны. Это может сэкономить много времени при наборе текста в проектах из нескольких файлов.
Использование заголовочных файлов стандартной библиотеки
Рассмотрим следующую программу:
#include int main()
Эта программа печатает « Hello, world! » в консоль с помощью std::cout . Однако эта программа никогда не предоставляла определение или объявление для std::cout , поэтому как компилятор узнает, что такое std::cout ?
Ответ заключается в том, что std::cout был предварительно объявлен в заголовочном файле « iostream ». Когда мы пишем #include , мы запрашиваем, чтобы препроцессор скопировал всё содержимое (включая предварительные объявления для std::cout ) из файла с именем « iostream » в файл, выполняющий #include .
Ключевой момент
Когда вы включаете файл с помощью #include , содержимое включаемого файла вставляется в точке включения. Это удобный способ извлечения объявлений из другого файла.
Подумайте, что бы произошло, если бы заголовок iostream не существовал. Каждый раз, когда вы хотели бы использовать std::cout , вам приходилось бы вручную вводить или копировать все объявления, связанные с std::cout , в начало каждого файла, который использовал бы std::cout ! Для этого потребуется много знаний о том, как реализован std::cout , и потребуется много работы. Хуже того, если бы прототип функции изменился, нам пришлось бы вручную обновлять все предварительные объявления. Намного проще просто включить iostream с помощью #include !
Когда дело доходит до функций и переменных, стоит помнить, что заголовочные файлы обычно содержат только объявления функций и переменных, а не их определения (в противном случае может произойти нарушение правила одного определения). std::cout объявлен в заголовке iostream, но определен как часть стандартной библиотеки C++, которая автоматически подключается к вашей программе на этапе линкера.

Лучшая практика
Заголовочные файлы обычно не должны содержать определений функций и переменных, чтобы не нарушать правило одного определения. Исключение сделано для символьных констант (которые мы рассмотрим в уроке «4.14 – const, constexpr и символьные константы»).
Написание собственных заголовочных файлов
А теперь вернемся к примеру, который мы обсуждали в предыдущем уроке. Когда мы закончили, у нас было два файла, add.cpp и main.cpp , которые выглядели так:
int add(int x, int y)
#include int add(int x, int y); // предварительное объявление с использованием прототипа функции int main()
(Если вы воссоздаете этот пример с нуля, не забудьте добавить add.cpp в свой проект, чтобы он компилировался).
В этом примере мы использовали предварительное объявление, чтобы при компиляции main.cpp компилятор знал, что такое идентификатор add . Как упоминалось ранее, добавление предварительных объявлений для каждой функции, которую вы хотите использовать, и которая находится в другом файле, вручную может быстро стать утомительным.
Давайте напишем заголовочный файл, чтобы избавиться от этого бремени. Написать заголовочный файл на удивление легко, поскольку файлы заголовков состоят только из двух частей:
- защита заголовка, о которой мы поговорим более подробно в следующем уроке («2.11 – Защита заголовков»);
- фактическое содержимое файла заголовка, которое должно быть предварительными объявлениями для всех идентификаторов, которые мы хотим, чтобы другие файлы могли видеть.
Добавление заголовочного файла в проект работает аналогично добавлению исходного файла (рассматривается в уроке «2.7 – Программы с несколькими файлами исходного кода»). Если вы используете IDE, выполните такие же действия и при появлении запроса выберите Файл заголовка (или C/C++ header) вместо Файла С++ (или C/C++ source). Если вы используете командную строку, просто создайте новый файл в своем любимом редакторе.
Лучшая практика
При именовании файлов заголовков используйте расширение .h .
Заголовочные файлы часто идут в паре с файлами исходного кода, при этом заголовочный файл предоставляет предварительные объявления для соответствующего исходного файла. Поскольку наш заголовочный файл будет содержать предварительное объявление для функций, определенных в add.cpp , мы назовем наш новый заголовочный файл add.h .
Лучшая практика
Если заголовочный файл идет в паре с файлом исходного кода (например, add.h с add.cpp ), они оба должны иметь одинаковое базовое имя ( add ).
Вот наш завершенный заголовочный файл:
// 1) У нас здесь на самом деле должна быть защита заголовка, // но для простоты мы опустим ее (мы рассмотрим защиту заголовков в следующем уроке) // 2) Это содержимое файла .h, где идут объявления int add(int x, int y); // прототип функции для add.h - не забудьте точку с запятой!
Чтобы использовать этот заголовочный файл в main.cpp , мы должны включить его с помощью #include (используя кавычки, а не угловые скобки).
#include // Вставляем содержимое add.h в этот момент. // Обратите внимание на использование здесь двойных кавычек. #include "add.h" int main()
int add(int x, int y)
Когда препроцессор обрабатывает строку #include "add.h" , он копирует содержимое add.h в текущий файл в эту точку. Поскольку наш add.h содержит предварительное объявление для функции add , это предварительное объявление будет скопировано в main.cpp . Конечным результатом является программа, которая функционально аналогична той, в которой мы вручную добавили предварительное объявление вверху main.cpp .
Следовательно, наша программа будет правильно компилироваться и компоноваться.

Включение заголовочного файла в соответствующий исходный файл
Позже вы увидите, что большинство исходных файлов включают свой соответствующий заголовочный файл, даже если он им не нужен. Зачем?
Включение заголовочного файла в исходный файл увеличивает прямую совместимость. Очень вероятно, что в будущем вы добавите больше функций или измените существующие таким образом, что им нужно будет знать о существовании друг друга.
Когда мы углубимся в изучение стандартной библиотеки, вы будете включать множество заголовочных файлов библиотек. Если вам потребовалось включение в заголовочном файле, оно, вероятно, понадобилось вам для объявления функции. Это означает, что вам также потребуется такое же включение в исходный файл. Это приведет к тому, что в исходном файле у вас будет копия включений заголовочного файла. Включив заголовочный файл в исходный файл, исходный файл получит доступ ко всему, к чему имел доступ заголовочный файл.
При разработке библиотеки включение заголовочного файла в исходный файл может даже помочь в раннем обнаружении ошибок.
Лучшая практика
При написании исходного файла включите в него соответствующий заголовочный файл (если он существует), даже если он вам пока не нужен.
Поиск и устранение проблем
Если вы получаете ошибку компилятора, указывающую, что add.h не найден, убедитесь, что файл действительно называется add.h . В зависимости от того, как вы его создали и назвали, возможно, файл может иметь имя вроде add (без расширения), add.h.txt или add.hpp . Также убедитесь, что он находится в том же каталоге, что и остальные исходные файлы.
Если вы получаете сообщение об ошибке компоновщика о том, что добавление функции не определено, убедитесь, что вы добавили в проект файл add.cpp , чтобы определение для функции add можно было слинковать в программе.
Угловые скобки и двойные кавычки
Вам, наверное, интересно, почему мы используем угловые скобки для iostream и двойные кавычки для add.h . Возможно, что заголовочные файлы с таким же именем могут существовать в нескольких каталогах. Использование угловых скобок и двойных кавычек помогает компилятору понять, где ему следует искать заголовочные файлы.
Когда мы используем угловые скобки, мы сообщаем препроцессору, что это заголовочный файл, который мы не писали сами. Компилятор будет искать заголовок только в каталогах, указанных в каталогах включаемых файлов (include directories). Каталоги включаемых файлов настраиваются как часть вашего проекта / настроек IDE / настроек компилятора и обычно по умолчанию используются для каталогов, содержащих заголовочные файлы, которые поставляются с вашим компилятором и/или ОС. Компилятор не будет искать заголовочный файл в каталоге исходного кода вашего проекта.
Когда мы используем двойные кавычки, мы сообщаем препроцессору, что это заголовочный файл, который написали мы. Компилятор сначала будет искать этот заголовочный файл в текущем каталоге. Если он не сможет найти там подходящий заголовочный файл, он будет искать его в каталогах включаемых файлов.
Правило
Используйте двойные кавычки, чтобы включать заголовочные файлы, которые написали вы или которые, как ожидается, будут найдены в текущем каталоге. Угловые скобки используйте, чтобы включать заголовочные файлы, которые поставляются с вашим компилятором, ОС или сторонними библиотеками, которые вы установили в другом месте своей системы.
Почему у iostream нет расширения .h ?
Другой часто задаваемый вопрос: «Почему iostream (или любой другой заголовочный файл стандартной библиотеки) не имеет расширения .h ?». Ответ заключается в том, что iostream.h – это другой заголовочный файл, отличающийся от iostream ! Для объяснения требуется небольшой урок истории.
Когда C++ был только создан, все файлы в стандартной библиотеке оканчивались расширением .h . Жизнь была последовательной, и это было хорошо. Исходные версии cout и cin были объявлены в iostream.h . Когда комитет ANSI стандартизировал язык, они решили переместить все функции стандартной библиотеки в пространство имен std , чтобы избежать конфликтов имен с пользовательскими идентификаторами. Однако это представляло проблему: если бы они переместили всю функциональность в пространство имен std , ни одна из старых программ (включая iostream.h ) больше не работала бы!
Чтобы обойти эту проблему, был представлен новый набор заголовочных файлов, которые используют те же имена, но не имеют расширения .h . Все функции в этих новых заголовочных файлах находятся в пространстве имен std . Таким образом, старые программы, содержащие #include , не нужно переписывать, а новые программы могут использовать #include .
Кроме того, многие библиотеки, унаследованные от C, которые всё еще используются в C++, получили префикс c (например, stdlib.h стал cstdlib ). Функциональные возможности этих библиотек также были перенесены в пространство имен std , чтобы избежать конфликтов имен.
Лучшая практика
При включении заголовочного файла из стандартной библиотеки используйте версию без расширения (без .h ), если она существует. Пользовательские заголовочные файлы по-прежнему должны использовать расширение .h .
Включение заголовочных файлов из других каталогов
Другой распространенный вопрос связан с тем, как включать заголовочные файлы из других каталогов.
Один (плохой) способ сделать это – добавить относительный путь к заголовочному файлу, который вы хотите включить как часть строки #include . Например:
#include "headers/myHeader.h" #include "../moreHeaders/myOtherHeader.h"
Хотя это будет компилироваться (при условии, что файлы существуют в этих относительных каталогах), обратная сторона этого подхода состоит в том, что он требует от вас отражения структуры каталогов в вашем коде. Если вы когда-нибудь обновите структуру каталогов, ваш код больше не будет работать.
Лучший способ – сообщить вашему компилятору или IDE, что у вас есть куча заголовочных файлов в каком-то другом месте, чтобы он смотрел туда, когда не может найти их в текущем каталоге. Обычно это можно сделать, установив путь включения (include path) или каталог поиска (search directory) в настройках проекта в IDE.
Для пользователей Visual Studio
Кликните правой кнопкой мыши на своем проекте в обозревателе решений и выберите Свойства (Properties), затем вкладку Каталоги VC++.(VC++ Directories). Здесь вы увидите строку с названием «Включаемые каталоги» (Include Directories). Добавьте каталоги, в которых компилятор должен искать дополнительные заголовочные файлы.
Для пользователей Code::Blocks
В Code:: Blocks перейдите в меню Project (Проект) и выберите Build Options (Параметры сборки), затем вкладку Search directories (Каталоги поиска). Добавьте каталоги, в которых компилятор должен искать дополнительные заголовочные файлы.
Для пользователей GCC/G++
Используя g++, вы можете использовать параметр -I , чтобы указать альтернативный каталог для включения.
g++ -o main -I/source/includes main.cpp
Хороший момент в этом подходе заключается в том, что если вы когда-нибудь измените структуру каталогов, вам нужно будет изменить только одну настройку компилятора или IDE, а не каждый файл кода.
Заголовочные файлы могут включать другие заголовочные файлы
Обычно для заголовочных файлов требуется объявление или определение, которое находится в другом заголовочном файле. Из-за этого заголовочные файлы часто включают с помощью #include другие заголовочные файлы.
Когда ваш исходный файл включает с помощью #include первый заголовочный файл, вы также получите любые другие заголовочные файлы, которые были включены в первый заголовочный файл (и любые заголовочные файлы, которые были включены в предыдущие, и т.д.). Эти дополнительные заголовочные файлы иногда называют «транзитивными включениями», поскольку они включаются неявно.
Содержимое этих транзитивных включений доступно для использования в вашем файле исходного кода. Однако не следует полагаться на содержимое заголовков, которые включены транзитивно. Реализация заголовочных файлов может со временем меняться или отличаться в разных системах. Если это произойдет, ваш код может компилироваться только на определенных системах или может компилироваться сейчас, но перестать в будущем. Этого легко избежать, явно включив все заголовочные файлы, необходимые для содержимого вашего файла исходного кода.
Лучшая практика
Каждый файл должен явно включать с #include все заголовочные файлы, необходимые для компиляции. Не полагайтесь на заголовочные файлы, включенные транзитивно из других заголовков.
К сожалению, нет простого способа определить, полагается ли ваш файл кода случайно на содержимое заголовочного файла, который был включен другим заголовочным файлом.
Вопрос: Я не включил , и моя программа всё равно работала! Почему?
Это один из наиболее часто задаваемых вопросов. Ответ: скорее всего, он работает, потому что вы включили какой-то другой заголовок (например, ), который сам включает . Несмотря на то, что ваша программа будет компилироваться, в соответствии с приведенными выше рекомендациями вам не следует полагаться на это. То, что компилируется у вас, может не компилироваться на машине друга.
Порядок #include заголовочных файлов
Если ваши заголовочные файлы написаны правильно и включают с #include всё, что им нужно, порядок включения не имеет значения. Однако включение заголовочных файлов в определенном порядке может помочь выявить ошибки, когда заголовочные файлы могут не включать в себя всё, что им нужно.
Лучшая практика
Упорядочьте свои включения с #include следующим образом: сначала ваши собственные пользовательские заголовки, затем заголовки сторонних библиотек, затем заголовки стандартных библиотек; заголовки в каждом разделе должны быть отсортированы в алфавитном порядке.
Таким образом, если в одном из ваших пользовательских заголовков отсутствует #include для заголовка сторонней библиотеки или стандартной библиотеки, это с большей вероятностью вызовет ошибку компиляции, чтобы вы могли ее исправить.
Рекомендации по использованию заголовочных файлов
Вот еще несколько рекомендаций по созданию и использованию заголовочных файлов.
- Всегда включайте защиту заголовков (мы рассмотрим это в следующем уроке).
- Не определяйте переменные и функции в файлах заголовков (глобальные константы являются исключением – мы рассмотрим их позже)
- Давайте файлам заголовков те же имена, что и исходным файлам, с которыми они связаны (например, grades.h идет в паре с grades.cpp ).
- Каждый заголовочный файл должен иметь конкретное назначение и быть максимально независимым. Например, вы можете поместить все объявления, относящиеся к функциональности A , в A.h , а все объявления, относящиеся к функциональности B , в B.h . Таким образом, если позже вам нужен будет только A , вы можете просто включить A.h и не получать ничего, связанного с B .
- Учитывайте, какие заголовки вам нужно явно включить для функций, которые вы используете в своих файлах исходного кода.
- Каждый заголовок, который вы пишете, должен компилироваться сам по себе (он должен включать с #include все необходимые зависимости)
- Включайте с #include только то, что вам нужно (не включайте всё только потому, что вы можете).
- Не включайте с #include файлы .cpp .
Для чего нужны заголовочные файлы?
Ещё раз всем здрасьте , последний вопрос в котором я не могу разобраться - Для чего нужны заголовочные файлы .
Для чего нужны эти файлы .h объясните мне на русском языке а не на теоретическом .
Ну и пример что бы до конца понел , спасибо заранее
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

Для чего нужны файлы с расширением .h, .c?
Не подскажите, для чего нужен (.h) и (.c) файл? А (.cpp)? Я читал, что это заголовочный файл, но за.
Заголовочные файлы .h, файлы исходного когда c/c++ и установление связи между ними
Всем добрый вечер!) Относительно недавно стал изучать c/c++, хочу полюбопытствовать ,так как.
Работа в Visual Studio 2015 - как добавить файлы исходного кода и заголовочные файлы?
Приветствую всех! Столкнулся с тем, что решая задачи по книге Лафоре про графику, не смог добавить.
Для чего нужны указатели?
Кто может объяснить для чего нужны указатели и смысл их? в интернете одна муть и еще для чего нужно.
Форумчанин
![]()
![]()
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
Представьте, что вы написали программу в миллион строк кода. А потом оказалось, что туда надо внести малюсенькие изменения, для начала вам надо в этих миллион строках как то сориентироваться, ну да ладно, вы же не лыком шиты, вы компьютерщик со стажем, Ctrl + F, усмехаетесь вы. Ну и через несколько итераций поиска вы все же находите нужную вам часть, потом понимаете, что она то функционирует нормально, вы снова набираете Ctrl + F и ищите другую часть и так долго-долго.
Но далее. Вы нашли наконец причину ошибки и исправили её. Представьте, сколько будет длиться компиляция всего файла? А если с первого раза ошибку не удалось искоренить, идем в начало?
Часто программисты отделяют части кода, которые можно использовать потом повторно, просто включив их, или просто разъединяя все по логическим маленьким кирпичикам, чтобы было легче потом ориентироваться, или разделяют код, чтобы компиляция шла не по несколько часов. Ведь при изменении лишь .h файла мы не будем трогать весь большой проект.
Надеюсь, аргументы показались вам достаточно вескими.