Организация файлов заголовков классов C ++ - PullRequest
49 голосов
/ 06 декабря 2008

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

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

Ответы [ 6 ]

66 голосов
/ 06 декабря 2008

Некоторые общие рекомендации:

  • Соедините ваши интерфейсы с реализациями. Если у вас есть foo.cxx, все, что там определено, лучше объявить в foo.h.
  • Убедитесь, что каждый заголовочный файл # включает все другие необходимые заголовки или предварительные объявления, необходимые для независимой компиляции.
  • Не поддавайтесь искушению создать заголовок "все". Они всегда в беде.
  • Поместите набор связанных (и взаимозависимых) функций в один файл. Java и другие среды поддерживают один класс на файл. С C ++ часто требуется один набор классов на файл. Это зависит от структуры вашего кода.
  • Предпочитайте предварительное объявление, по возможности, #include с. Это позволяет вам нарушать зависимости циклического заголовка. По сути, для циклических зависимостей между отдельными файлами вам нужен граф зависимостей файлов, который выглядит примерно так:
    • A.cxx требуется A.h и B.h
    • B.cxx требуется A.h и B.h
    • A.h требуется B.h
    • B.h является независимым (и классы, определенные в A.h),

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

  • При необходимости используйте понятие «частные заголовки». То есть заголовочные файлы, которые требуются для нескольких исходных файлов, но никогда не требуются для открытого интерфейса. Это может быть файл с общими встроенными функциями, макросами или внутренними константами.
  • Отделите ваш публичный интерфейс от вашей частной реализации на уровне файловой системы. Я склонен использовать подкаталоги include/ и src/ в моих проектах C или C ++, где include/ содержит все мои публичные заголовки, а src/ содержит все мои источники. и частные заголовки.

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

8 голосов
/ 06 декабря 2008

Ознакомьтесь со стандартами кодирования C и C ++ в Центре космических полетов имени Годдарда НАСА . Единственное правило, которое я специально отметил в стандарте C и приняло в своем собственном коде, - это правило, которое обеспечивает «автономную» природу заголовочных файлов. В файле реализации xxx.cpp для заголовка xxx.h убедитесь, что xxx.h является первым включенным заголовком. Если заголовок не является автономным в любое время, то компиляция не удастся. Это красиво простое и эффективное правило.

Единственный раз, когда у вас не получится, если вы портируете между компьютерами, а заголовок xxx.h включает, скажем, <pqr.h>, но <pqr.h> требует, чтобы средства, которые оказывались доступными заголовком <abc.h> на исходная платформа (т. е. <pqr.h> включает <abc.h>), но <abc.h> не предоставляет доступ к объектам на другой платформе (вместо этого они def.h, но <pqr.h> не включает <def.h>). Это не ошибка правила, и проблему легче диагностировать и устранить, если вы следуете правилу.

6 голосов
/ 06 декабря 2008

Проверьте раздел файла заголовка в Руководство по стилю Google

5 голосов
/ 06 декабря 2008

Том отвечает отлично!

Единственное, что я хотел бы добавить, - это никогда не использовать «объявления» в заголовочных файлах. Они должны быть разрешены только в файлах реализации, например foo.cpp.

Логика для этого хорошо описана в превосходной книге «Ускоренный C ++» ( Ссылка Amazon - продезинфицирована для сценаристов детские ссылки нацистов)

3 голосов
/ 30 июня 2013

Я хотел бы добавить одну очень хорошую практику (как в C, так и в C ++), которую часто оставляют:

foo.c

#include "foo.h" // always the first directive

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

Если в какой-то момент вам нужно что-то поставить перед включением этого заголовка (кроме, конечно, комментариев), то, скорее всего, вы делаете что-то не так. Если вы действительно не знаете, что делаете ... что приводит к другому, более важному правилу => комментируйте свои хаки!

3 голосов
/ 08 декабря 2008

Еще один пункт в дополнение к другим здесь:

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

Кажется очевидным, но я вижу это часто.

...