2016-11-13 2 views
1

Когда необходимо отдельно объявить класс в файле «.h» и предоставить реализацию функций в файле «.cpp»?Когда необходимо отдельно объявить класс в файле «.h» и предоставить реализацию функций в файле «.cpp» в C++?

+1

Исторические причины, когда время программиста было дешевле машинного времени, поэтому вы дадите компилятору '.h' знать, чего ожидать и выполнить его проверки. Ради совместимости с каменным возрастом программирования это все еще используется сегодня. – Robert

+2

@Robert Используется для сокращения времени компиляции, а не только для «совместимости с каменным возрастом программирования». Время компиляции может быть раздражающим. –

+0

@ Peregring-lk Если вы сохраняете объектные файлы, вы все равно сокращаете время компиляции. Компилятор мог просто посмотреть '.cpp' вместо' .h'. Таким образом, программисту не придется дублировать всю информацию между файлами '.h' и' .cpp'. – Robert

ответ

0

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

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

+0

Я даже не согласен с тем, что файлы заголовков хороши для скрытия деталей реализации, так как вы увидите все частные члены класса в файле заголовка. – Robert

+0

@Robert true, если вы посмотрите на файлы заголовков, вы знаете больше, чем вам нужно знать о реализации (т. Е. О частных членах). Я не упоминал о скрытии информации. Я только упомянул, что удобнее смотреть на заголовок класса, чтобы ** использовать ** его. – artm

1

Это делается так, что вы только создаете код класса один раз. Если вы поместите код класса в файл .h, то каждый файл, который забирает .h (для доступа к публичным функциям класса), также продублирует код класса. Компилятор с радостью сделает это за вас. Компилятор, однако, сильно пожалуется о дублировании lvalues ​​в пространстве имен.

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

1

Не обязательно, насколько это касается языка C++. Вы можете поместить все методы класса inline в файл .h.

Однако, поставив реализации в отдельную .cpp предлагает множество преимуществ, таких как:

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

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

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

+0

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

1

Если вы хотите использовать объявления для осуществления/определения функции, декларации, которые вы не хотите, чтобы сделать видимыми в * .h файле, то необходимо было бы переместить определение функции отдельный файл.

0

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

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

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

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

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

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

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

Смежные вопросы