Зачем C ++ нужен отдельный заголовочный файл?
=============================================

Мы никогда не понимали, почему C ++ нуждается в отдельном заголовочном файле с теми же функциями, что и в файле .cpp. Это делает создание классов и их рефакторинг очень сложным и добавляет ненужные файлы в проект. И тогда возникает проблема с необходимостью включения заголовочных файлов, но с явной проверкой, если они уже были включены.

C ++ был ратифицирован в 1998 году, так почему же он разработан таким образом? Какие преимущества имеет наличие отдельного заголовочного файла?

Контрольный вопрос:Как компилятор находит файл .cpp с кодом в нем, когда я включаю только файл .h? Предполагается ли, что файл .cpp имеет то же имя, что и файл .h, или он просматривает все файлы в дереве каталогов?

Вы, кажется, спрашиваете об отделении определений от объявлений, хотя существуют и другие способы использования заголовочных файлов.

Ответ в том, что C ++ не "необходимость" этот. Если вы пометите все как встроенное (что в любом случае является автоматическим для функций-членов, определенных в определении класса), разделение не требуется. Вы можете просто определить все в заголовочных файлах.

Причины, по которым вы могли быхочу отделить являются:

Чтобы улучшить время сборки.Для ссылки на код, не имея источника для определений.Чтобы не отмечать все "в соответствии".Если ваш более общий вопрос "почему нетт С ++ идентичен Java? "тогда я должен спросить "почему ты пишешь C ++ вместо Java? " ;-п

А если серьезно, причина в том, что компилятор C ++ можетпросто достучаться до другой единицы перевода и выяснить, как использовать ее символы так, как это делает и делает javac. Заголовочный файл необходим, чтобы объявить компилятору, что он может ожидать быть доступным во время ссылки.

Так`#include` прямая текстовая замена. Если вы определите все в заголовочных файлах, препроцессор в итоге создаст огромную копию и вставку каждого исходного файла в вашем проекте и загрузит его в компилятор. Тот факт, что стандарт C ++ был ратифицирован в 1998 году, не имеет к этому никакого отношения.тот факт, что среда компиляции для C ++ так тесно основана на среде C.

Преобразование моих комментариев, чтобы ответить на ваш дополнительный вопрос:

Как компилятор находит файл .cpp с кодом в нем

Это нет, по крайней мере, не во время компиляции кода, который использовал файл заголовка. Функции, которые выре связываюсь против недаже не нужно писать, не говоря уже о компиляторе, зная, что`.cpp` подать ониЯ буду внутри. Все, что нужно знать вызывающему коду во время компиляции, выражается в объявлении функции. Во время ссылки вы предоставите список`.o` файлы, или статические, или динамические библиотеки, а действующий заголовок - это обещание, что определения функций где-то там будут.



Ну, вы можете прекрасно разработать C ++ без заголовочных файлов. Фактически некоторые библиотеки, которые интенсивно используют шаблоны, не используют парадигму заголовочных файлов / файлов кода (см. Boost). Но в C / C ++ нельзя использовать то, что не объявлено. Один из практических способов справиться с этим - использовать заголовочные файлы. Кроме того, вы получаете преимущество совместного использования интерфейса без совместного использования кода / реализации. И я думаю, что создатели C не предполагали этого: когда вы используете общие заголовочные файлы, вы должны использовать знаменитые:

на самом деле это не языковая функция, а практический способ борьбы с множественным включением.

Итак, я думаю, что когда создавался C, проблемы с предварительным объявлением были недооценены, и теперь при использовании языка высокого уровня, такого как C ++, нам приходится иметь дело с такого рода вещами.

Еще одно бремя для нас, бедных пользователей C ++ ...



C ++ был разработан для добавления современных возможностей языка программирования в инфраструктуру C, без необходимости менять что-либо в C,Т конкретно о самом языке.

Да, на данный момент (через 10 лет после первого стандарта C ++ и через 20 лет после того, как он начал серьезно расти в использовании), легко спросить, почемуу него есть правильная система модулей. Очевидно, что любой новый язык, разрабатываемый сегодня, не будет работать как C ++. Но это неТочка C ++.

Смысл C ++ в том, чтобы быть эволюционным, плавным продолжением существующей практики, только добавляя новые возможности, не нарушая (слишком часто) вещи, которые адекватно работают для его сообщества пользователей.

Это означает, что это делает некоторые вещи сложнее (особенно для людей, начинающих новый проект), а некоторые вещи легче (особенно для тех, кто поддерживает существующий код), чем другие языки.

Поэтому вместо того, чтобы ожидать, что C ++ превратится в C # (что было бы бессмысленно, поскольку у нас уже есть C #), почему бы просто не выбрать правильный инструмент для этой работы? Сам я стараюсь писать значительные куски новой функциональности на современном языке (я использую C #), и у меня есть большое количество существующих C ++, которые я храню в C ++, потому что не было бы никакой реальной ценности в переписывании этого все. В любом случае, они очень хорошо интегрируются, так чтов основном безболезненно.



На мой (ограниченный - я 'я обычно не разработчик C) понимая, это коренится в C. Помните, что C не знает, что такое классы или пространства имен, это 'Это всего лишь одна длинная программа. Кроме того, функции должны быть объявлены перед их использованием.

Например, следующее должно дать ошибку компилятора:

Ошибка должна быть в том, чтоSomeOtherFunction не объявлен потому что ты называешь это раньшедекларация Один из способов исправить это - переместить SomeOtherFunction над SomeFunction. Другой подход - сначала объявить сигнатуру функций:

Это позволяет компилятору узнать: где-то в коде есть функция SomeOtherFunction, которая возвращает void и не принимает никаких параметров. Поэтому, если вам нужен код, который пытается вызвать SomeOtherFunction, не паникуйте, а вместо этого отправляйтесь на его поиск.

Теперь представьте, что у вас есть SomeFunction и SomeOtherFunction в двух разных файлах .c. Затем вы должны #include "SomeOther.c» в некоторых Теперь добавьте немногочастный" функционирует SomeOther.c. Поскольку C не знает приватных функций, эта функция также будет доступна в Some.c.

Вот где приходят файлы .h: они определяют все функции (и переменные), которые вы хотитеЭкспорт» из .c файла, который может быть доступен в других .c файлах. Таким образом, вы получаете что-то вроде публичного / частного объема. Кроме того, вы можете передать этот файл .h другим людям без необходимости делиться своим исходным кодом - файлы .h также работают с скомпилированными файлами .lib.

Таким образом, главная причина на самом деле для удобства, для защиты исходного кода и для некоторого разделения между частями вашего приложения.

Это был С, хотя. C ++ представил классы и частные / публичные модификаторы, поэтому, хотя вы все еще можете спросить, нужны ли они, C ++ AFAIK по-прежнему требует объявления функций перед их использованием. Кроме того, многие разработчики C ++ являются или были разработчиками языка C и переняли свои концепции и привычки на C ++ - зачем менять то, что нет?Т сломан?



Ну, C ++ был ратифицирован в 1998 году, но он использовался гораздо дольше, и ратификация в первую очередь определяла текущее использование, а не навязывала структуру. И поскольку C ++ был основан на C, а C имеет заголовочные файлы, в C ++ они тоже есть.

Основная причина для заголовочных файлов состоит в том, чтобы включить отдельную компиляцию файлов и минимизировать зависимости.

Скажем, у меня есть foo.cpp, и я хочу использовать код из файлов bar.h / bar.cpp.

Я могу включитьbar.h» в foo.cpp, а затем запрограммируйте и скомпилируйте foo.cpp, даже если bar.cpp не 'не существует. Заголовочный файл действует как обещание компилятору, что классы / функции в bar.h будут существовать во время выполнения, и в нем есть все, что ему нужно уже знать.

Конечно, если функции в bar.h некогда я пытаюсь связать свою программу, у меня нет телт ссылку и яЯ получу ошибку.

Побочным эффектом является то, что вы можете дать пользователям файл заголовка, не раскрывая свой исходный код.

Другое заключается в том, что если вы измените реализацию своего кода в файле * .cpp, но вообще не измените заголовок, вам нужно только скомпилировать файл * .cpp вместо всего, что его использует. Конечно, если вы поместите много реализации в заголовочный файл, это станет менее полезным.



Некоторые люди считают заголовочные файлы преимуществом:

Утверждается, что он включает / обеспечивает / разрешает / разделяет интерфейс и реализацию - но обычно это не так. Заголовочные файлы полны деталей реализации (например, переменные-члены класса должны быть указаны в заголовке, даже если онине являются частью общедоступного интерфейса), и функции могут и часто определяются как встроенныев объявление класса в заголовке, снова разрушающее это разделение.Иногда говорят, что это улучшает время компиляции, потому что каждая единица перевода может обрабатываться независимо. И все же C ++, вероятно, самый медленный из существующих языков, когда дело доходит до компиляции. Часть причины - много многократных включений того же самого заголовка. Большое количество заголовков включено несколькими модулями перевода, что требует их многократного анализа.В конечном итоге, система заголовков является артефактом от 70 'с, когда C был разработан. Тогда у компьютеров было очень мало памяти, и хранение всего модуля в памяти просто не былот вариант. Компилятор должен был начать чтение файла сверху, а затем продолжить линейно через исходный код. Механизм заголовка позволяет это. Компилятор ненужно учитывать другие единицы перевода, просто нужно читать код сверху вниз.

И C ++ сохранил эту систему для обратной совместимости.

Сегодня это не имеет смысла. Это неэффективно, подвержено ошибкам и слишком сложно. Существуют гораздо лучшие способы разделить интерфейс и реализацию, еслитот была цель.

Однако одно из предложений для C ++ 0x заключалось в том, чтобы добавить правильную систему модулей, позволяющую компилировать код, подобный .NET или Java, в более крупные модули, причем все за один раз и без заголовков. Это предложение неЯ не верю в C ++ 0x, но я верю в этовсе еще в "мы'буду любить делать это позже категория. Возможно в TR2 или аналогичном.



Первое преимущество: если вы неЕсли у вас есть заголовочные файлы, вы должны будете включить исходные файлы в другие исходные файлы. Это приведет к повторной компиляции включаемых файлов при изменении включаемого файла.

Второе преимущество: это позволяет совместно использовать интерфейсы без разделения кода между различными подразделениями (разными разработчиками, командами, компаниями и т. Д.)



Это неМне нужен отдельный заголовочный файл с теми же функциями, что и в main. Это нужно только в том случае, если вы разрабатываете приложение, используя несколько файлов кода, и если вы используете функцию, которая не была ранее объявлена.

Это'Это действительно проблема масштаба.



C ++ был ратифицирован в 1998 году, так почему же он разработан таким образом? Какие преимущества имеет наличие отдельного заголовочного файла?

На самом деле, заголовочные файлы становятся очень полезными при первом рассмотрении программ. Проверка заголовочных файлов (с использованием только текстового редактора) дает вам обзор архитектуры программы, в отличие от других языков, где вам приходится использовать сложные инструменты для просмотра классов и их функции-члены.



C ++ делает это таким образом, потому что C сделал это таким образом, поэтому реальный вопрос заключается в том, почему C сделал это таким образом?[Википедия](https://en.wikipedia.org/wiki/Header_file) говорит немного об этом.

Более новые скомпилированные языки (такие как Java, C #) не используют предварительные объявления; идентификаторы распознаются автоматически из исходных файлов и считываются непосредственно из символов динамической библиотеки. Это означает, что заголовочные файлы не нужны.



Если вы хотите, чтобы компилятор обнаруживал символы, определенные в других файлах, автоматически, вы должны заставить программиста поместить эти файлы в предопределенные места (например, структура пакетов Java определяет структуру папок проекта). Я предпочитаю заголовочные файлы. Также вам понадобятся либо источники используемых вами библиотек, либо какой-то унифицированный способ размещения информации, необходимой компилятору, в двоичные файлы.



Я думаю, что настоящая (историческая) причина, лежащая в основе заголовочных файлов, была проще для разработчиков компиляторов ... но потом, заголовочные файлы**делать** дать преимущества.  
  
Проверьте[этот предыдущий пост](https://stackoverflow.com/questions/752793/should-c-eliminate-header-files) для дальнейшего обсуждения ...



Потребность в заголовочных файлах проистекает из ограничений, которые имеет компилятор для знания информации о типе для функций и / или переменных в других модулях. Скомпилированная программа или библиотека не содержит информацию о типе, требуемую компилятором для привязки к любым объектам, определенным в других модулях компиляции.

Чтобы компенсировать это ограничение, C и C ++ допускают объявления, и эти объявления могут быть включены в модули, которые используют их с помощью препроцессора.s #include директива.

Такие языки, как Java или C #, с другой стороны, содержат информацию, необходимую для связывания в компиляторе.s вывод (файл класса или сборка). Следовательно, больше нет необходимости поддерживать автономные объявления, включаемые клиентами модуля.

Причина, по которой информация о привязке не включается в выходные данные компилятора, проста: она не требуется во время выполнения (любая проверка типов выполняется во время компиляции). Это просто пустое место. Помните, что C / C ++ пришел из того времени, когда размер исполняемого файла или библиотеки действительно имел значение.