У меня есть следующие сомнения по поводу использования заголовочных файлов.
1 - Включить охранников после комментариев
/* Copyright Note and licence information (multiple lines) */
#ifndef FOO_H
#define FOO_H
// Header file contents
#endif
Херб Саттер в своей книге «Стандарты кодирования C++» говорит, что код, подобный приведенному выше, проблематичен. Он говорит, что операторы "#ifndef" должны появиться в первой строке файла заголовка. Я не считал это убедительным. Вы, ребята, за этим следите в заголовочных файлах?
2 - Использование пространств имен в файлах заголовков
#ifndef FOO_H
#define FOO_H
namespace FooNameSpace{
// Header file contents
}
#endif
Правильно ли используется приведенный выше код? Я имею в виду, вы используете пространства имен в файлах заголовков? Я знаю, почему импортировать пространство имен в файл заголовка бессмысленно, но как насчет объявления, подобного приведенному выше?
Если приведенный выше метод является правильным, как сделать «предварительная декларация» класса, находящегося в другом пространстве имен? Это похоже на
#ifndef FOO_H
#define FOO_H
namespace AnotherNameSpace{
class AnotherFoo; // forward declaration
}
namespace FooNameSpace{
// Use AnotherFoo here
}
#endif
«предварительная декларация» - единственный способ избежать «циклическая зависимость», верно?





Порядок включения охранников и комментариев - это чисто вопрос стиля - он не окажет заметного влияния на скорость компиляции.
Пространства имен абсолютно необходимо использовать в файлах заголовков для объявления функций, классов, глобальных объектов и т. д. Что вам следует сделать нет, так это использовать операторы using в файлах заголовков - невозможно неиспользовать что-то в исходном файле, который это включает, и вы не должны заставить включателей добавлять дополнительные элементы в глобальную область видимости. Если вам нужно использовать в заголовках что-то из других пространств имен, полностью уточняйте каждое имя. Иногда это может быть болезненно, но это действительно правильный поступок.
Примеры:
// WRONG!
using namespace std;
class MyClass
{
string stringVar;
};
// RIGHT
class MyClass
{
std::string stringVar;
};
Что касается прямого объявления классов в других пространствах имен, вы все правильно поняли. Просто не забывайте всегда квалифицировать AnotherFoo как AnotherNameSpace::AnotherFoo, когда вы ссылаетесь на него в заголовке. Действительно, предварительные объявления - единственный способ разорвать циклические зависимости.
Что касается №1, я не знаю каких-либо конкретных аргументов за или против. Многие компании придерживаются политики, согласно которой уведомление об авторских правах должно быть первым элементом в файле ПЕРЕД чем-либо другим или каким-либо значимым кодом (возможно, предполагается, что вы прочитаете информацию об авторских правах, прежде чем усвоите какой-либо код). Для этого #IFNDEF уже является кодом. С точки зрения юзабилити имеет смысл поставить на первое место авторские права, потому что глаз их игнорирует. Однако, на мой взгляд, все, что описывает модуль, должно идти после #ifndef.
1) Поскольку комментарии на самом деле ничего не делают, я сомневаюсь, что это имеет большое значение. Технически, однако, #include копировать и вставлять, поэтому размещение комментариев за пределами защиты заголовка может означать, что препроцессору придется потрудиться. Я не знаю, достаточно ли умен большинство компиляторов, чтобы оптимизировать для этого (т.е. если они удаляют комментарии перед этапом препроцессора), но вы, вероятно, не заметите, пока не дойдете до десятков тысяч файлов заголовков.
2) Верно. Если вы хотите поместить класс в пространство имен, и этот класс будет объявлен в файле заголовка, тогда он должен быть объявлен внутри пространства имен, которое, таким образом, должно быть в файле заголовка. И да, именно так вы вперед заявляете. И да, это основной инструмент для предотвращения циклической зависимости (вы также можете изменить свой дизайн, но в принципе нет ничего плохого в цикличности при условии, что два рассматриваемых класса ссылаются друг на друга только по ссылке или указателю и не вызывают никаких методов) .
Я слышал, что есть комментарии прежде, чем включенный охранник может вызвать некоторые компиляторы пропускают оптимизация. Если охранник самое первое, компилятор может распознать идиому и даже не потрудитесь открыть заголовок для последующие включает. В моем собственном код, комментарии обычно предшествуют включить охранника. Я никогда не потрудился проверить, есть ли у этого какое-либо воздействие или нет. И я, вероятно, никогда не буду (но если кто-то еще это сделает, меня будут интересовать результаты).
Конечно, заголовки должны включать
пространства имен - иначе ничего
полезный может быть внутри
пространство имен. Однако, как вы
упомянуто, заголовки не должны
'импорт' (за неимением лучшего слова)
пространства имен в единицу компиляции
с директивой using.
Я не думаю, что добавление комментариев влияет на производительность, как указано в ответе Адама на этот пост.
Я использовал свои пространства имен в файлах заголовков, что, если вы определите свой собственный строковый класс, так что он будет конфликтовать с строковым классом пространства имен std.
Использование ключевого слова using в точности не является неправильным (поскольку оно дает вам много удобства и намного меньше возможностей для ввода перед всеми вашими переменными)
В исходном файле использование "using" совсем не неправильно, но в файле заголовка это очень неправильно.