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

Я думаю, что ноутбук был изобретен приблизительно в 1980, и я также думаю, что разработка ноутбуков и портативной вычислительной техники изменила много жизней людей - конечно, те из нас, кто работает в IT, или кто использует компьютеры и перемещение.

124
задан Marius 20 August 2009 в 14:18
поделиться

13 ответов

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

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

Причины, по которым вы можете разделить , следующие:

  1. Чтобы сократить время сборки.
  2. Чтобы связать код без наличия источника для определений .
  3. Чтобы не отмечать все как «встроенное».

Если ваш более общий вопрос: «Почему C ++ не идентичен Java?», Тогда я должен спросить: «Почему вы пишете C ++ вместо Java?» " ;-p

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

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

Преобразование моих комментариев для ответа на ваш последующий вопрос:

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

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

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

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

99
ответ дан 24 November 2019 в 01:05
поделиться

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

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

В конечном счете, система заголовков является артефактом 70-х годов, когда был разработан C. В то время у компьютеров было очень мало памяти, и хранить весь модуль в памяти было просто невозможно. Компилятор должен был начать чтение файла сверху, а затем продолжить линейно по исходному коду. Механизм заголовка позволяет это. Компилятор не должен учитывать другие единицы трансляции, он просто должен читать код сверху вниз.

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

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

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

57
ответ дан 24 November 2019 в 01:05
поделиться

C++ does it that way because C did it that way, so the real question is why did C do it that way? Wikipedia speaks a little to this.

Newer compiled languages (such as Java, C#) do not use forward declarations; identifiers are recognized automatically from source files and read directly from dynamic library symbols. This means header files are not needed.

83
ответ дан 24 November 2019 в 01:05
поделиться

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

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

void SomeFunction() {
    SomeOtherFunction();
}

void SomeOtherFunction() {
    printf("What?");
}

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

void SomeOtherFunction();

void SomeFunction() {
    SomeOtherFunction();
}

void SomeOtherFunction() {
    printf("What?");
}

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

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

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

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

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

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

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

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

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

26
ответ дан 24 November 2019 в 01:05
поделиться

First advantage: If you don't have header files, you would have to include source files in other source files. This would cause the including files to be compiled again when the included file changes.

Second advantage: It allows sharing the interfaces without sharing the code between different units (different developers, teams, companies etc..)

10
ответ дан 24 November 2019 в 01:05
поделиться

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

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

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

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

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

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

5
ответ дан 24 November 2019 в 01:05
поделиться

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

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

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

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

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

4
ответ дан 24 November 2019 в 01:05
поделиться

It doesn't need a separate header file with the same functions as in main. It only needs it if you develop an application using multiple code files and if you use a function that was not previously declared.

It's really a scope problem.

3
ответ дан 24 November 2019 в 01:05
поделиться

Ну, 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 вместо всего, что его использует. Конечно, если вы поместите много реализаций в файл заголовка, это станет менее полезным.

cpp вместо всего, что его использует. Конечно, если вы поместите много реализаций в файл заголовка, это станет менее полезным.

cpp вместо всего, что его использует. Конечно, если вы поместите много реализаций в файл заголовка, это станет менее полезным.

3
ответ дан 24 November 2019 в 01:05
поделиться

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

#ifndef MY_HEADER_SWEET_GUARDIAN
#define MY_HEADER_SWEET_GUARDIAN

// [...]
// my header
// [...]

#endif // MY_HEADER_SWEET_GUARDIAN

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

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

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

1
ответ дан 24 November 2019 в 01:05
поделиться

I think the real (historical) reason behind header files was making like easier for compiler developers... but then, header files do give advantages.
Check this previous post for more discussions...

1
ответ дан 24 November 2019 в 01:05
поделиться

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

1
ответ дан 24 November 2019 в 01:05
поделиться

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

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

1
ответ дан 24 November 2019 в 01:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: