Должен ли C ++ исключать заголовочные файлы? - PullRequest
68 голосов
/ 15 апреля 2009

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

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

Я имею в виду текущие и будущие версии стандарта C ++.

Ответы [ 17 ]

75 голосов
/ 15 апреля 2009

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

33 голосов
/ 15 апреля 2009

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

Это также позволяет немного упростить работу с SDK. Вы можете предоставить только заголовки и некоторые библиотеки. Конечно, есть способы обойти это, которые используют другие языки.

31 голосов
/ 15 апреля 2009

Четный Бьярн Страуструп назвал заголовочные файлы клуджем.

Но без стандартного двоичного формата, который включает необходимые метаданные (например, файлы классов Java или файлы .Net PE), я не вижу способа реализовать эту функцию. Раздвоенный ELF или двоичный файл a.out не содержит много информации, которую вам нужно извлечь. И я не думаю, что эта информация когда-либо хранится в файлах Windows XCOFF.

22 голосов
/ 15 апреля 2009

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

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

Возможно, если intellisense в Visual Studio работал лучше для C ++, у меня не было бы веской причины так часто обращаться к файлам .h, но даже в VS2008, intellisense в C ++ не может касаться C #

18 голосов
/ 16 апреля 2009

In Дизайн и эволюция C ++ , Страуструп выдвигает еще одну причину ...

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

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

15 голосов
/ 15 апреля 2009

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

На самом деле это хорошая идея. Когда C был создан, C и Unix были своего рода парой. C портировал Unix, Unix запускал C. Таким образом, C и Unix могли быстро распространяться с платформы на платформу, тогда как ОС, основанная на сборке, должна была быть полностью переписана для переноса.

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

Эти элементы, указатели, файлы заголовков и т. Д. На самом деле не дают никаких преимуществ перед другой системой. Прилагая больше усилий к компилятору, вы можете скомпилировать ссылочный объект так же легко, как указатель на точно такой же объектный код. Это то, что сейчас делает C ++.

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


Кажется, что некоторые люди на самом деле не верят, что C был написан для порта Unix, поэтому здесь: ( из )

Первая версия UNIX была написана на языке ассемблера, но Томпсона Предполагалось, что это будет написано на языке высокого уровня.

Томпсон впервые попытался использовать в 1971 году Фортран на PDP-7, но сдался после первого дня. Затем он написал очень простой язык, который он назвал B, который он получил на PDP-7. Это работал, но были проблемы. Во-первых, потому что реализация была интерпретировать, это всегда будет медленный. Во-вторых, основные понятия B, который был основан на слово-ориентированных BCPL, просто не были подходящими для байт-ориентированная машина как новая PDP-11.

Ричи использовал PDP-11 для добавления типов к B, который некоторое время назывался NB для «нового Б», а затем он начал написать компилятор для него. "Таким образом Первая фаза C была действительно эти два фазы в короткой последовательности, во-первых, некоторые языковые изменения от B, действительно, добавление структуры типа без слишком много изменений в синтаксисе; и делать компилятор, "сказал Ричи.

«Второй этап был медленнее», - сказал он. переписать UNIX на C. Thompson началось летом 1972 года, но было две проблемы: выяснить, как бежать основные подпрограммы, то есть, как переключить управление с одного процесса на другой; и сложность в получении правильная структура данных, так как оригинальной версии C не было структур.

"Сочетание причин, вызванных Кен сдастся за лето " Ричи сказал. «За год я добавил структуры и, вероятно, сделали код компилятора несколько лучше - лучший код - и так далее лето, когда мы сделали согласованные усилия и на самом деле сделали повтор вся операционная система в Си. "


Вот прекрасный пример того, что я имею в виду. Из комментариев:

Указатели существуют только для облегчения написания компилятора? Нет. Указатели существуют, потому что они - самая простая абстракция над идеей косвенности. - Адам Розенфилд (час назад)

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

Проблема? Чтобы реализовать массивы так же эффективно, как указатели, вам нужно добавить ОГРОМНУЮ кучу кода в ваш компилятор.

Нет причины, по которой они не могли бы создать C без указателей, но с таким кодом:

int i=0;
while(src[++i])
    dest[i]=src[i];

потребуется много усилий (со стороны компиляторов), чтобы выделить явные дополнения i + src и i + dest и заставить его создать тот же код, что и это:

while(*(dest++) = *(src++))
    ;

Факторинг этой переменной "i" после факта - ЖЕСТКИЙ. Новые компиляторы могут это делать, но тогда это было просто невозможно, и ОС, работающей на этом дрянном оборудовании, требовалась небольшая оптимизация, подобная этой.

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

14 голосов
/ 15 апреля 2009

Если вы хотите C ++ без заголовочных файлов, тогда у меня для вас хорошие новости.

Он уже существует и называется D (http://www.digitalmars.com/d/index.html)

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

8 голосов
/ 13 июля 2009

Многие люди знают о недостатках заголовочных файлов, и есть идеи ввести более мощную модульную систему в C ++. Возможно, вы захотите взглянуть на Модули в C ++ (Редакция 5) от Daveed Vandevoorde.

8 голосов
/ 15 апреля 2009

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

Поскольку C ++ разработан прямо сейчас, вам нужны прототипы - как и в C - для статической проверки любого скомпилированного кода, который ссылается на внешние функции и классы. Без заголовочных файлов вы должны были бы напечатать эти определения классов и объявления функций перед их использованием. Чтобы С ++ не использовал заголовочные файлы, вам нужно добавить в язык функцию, которая будет поддерживать что-то вроде ключевого слова Java import. Это было бы серьезным дополнением и изменением; ответить на ваш вопрос о том, будет ли это практичным: я так не думаю - совсем нет.

2 голосов
/ 16 апреля 2009

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

...