Должна ли вспомогательная функция входить в заголовок или в файл реализации?
При написании вспомогательного метода для класса в С++, следует ли его объявить как частный метод в определении класса в файле заголовка (.h)? Например:
/*Foo.h*/
class Foo {
public:
int bar();
private:
int helper();
};
...
/*Foo.cpp*/
...
int foo::bar() {
int something = this->helper();
}
int foo::helper() {
...
}
Или, наоборот, лучше не объявлять его как частный член класса, а вместо этого просто делать его самостоятельной функцией в реализации?
/*Foo.h*/
class Foo {
public:
int bar();
};
...
/*Foo.cpp*/
...
int Foo::bar() {
int something = helper();
...
}
int helper() {
...
}
Ответы
Ответ 1
Свободная функция в файле реализации улучшает инкапсуляцию: ему не требуется декларация в заголовке, поэтому перекомпиляция клиентского кода при изменении его подписи по какой-либо причине не требуется. Для меня это достаточно хорошая причина, чтобы предпочесть этот вариант, когда это возможно. (Обязательно поместите его в анонимное пространство имен, чтобы предотвратить столкновения идентификаторов во время ссылки.)
Однако метод private
имеет доступ к экземпляру класса и его частным частям с помощью указателя this
. Если ему нужен такой доступ, то он должен быть либо методом, либо friend
. В обоих случаях он будет отображаться в определении класса (заголовочный файл), а методы просто более удобны, чем друзья.
Ответ 2
Если ваша вспомогательная функция имеет смысл быть методом объекта, я почти всегда предпочел бы сделать ее функцией-членом, поэтому есть неявный указатель this
, а не передать Foo *
вспомогательной функции.
Если вспомогательная функция не должна быть методом объекта (то есть ей не нужен доступ к элементам данных или другим функциям-членам), тогда сделайте ее автономной функцией (static
или в анонимное пространство имен, предпочтительно).
Ответ 3
Это немного субъективно, я думаю.
На мой взгляд, это зависит от того, имеет ли он какое-либо отношение к членам класса и/или ожидаете ли вы, что классы друзей будут использовать его (или производные классы в случае доступа protected
).
Если функция фактически не работает ни с одним из членов, и никто ее не интересует, вы должны сохранить ее в файле реализации как статическую функцию. Кроме того, если это операция, которая должна быть быстрой, вы можете воспользоваться этой возможностью, чтобы сделать ее inline
.
И наоборот, если функция работает над классом или может иметь дополнительные возможности использования в производных или связанных классах, сделайте ее членом.
Ответ 4
Моя позиция заключается в том, что заголовок содержит как можно меньше рекламы при достижении желаемых свойств дизайна и макета. Если есть опция, она переходит в исходный код. Некоторые внутренние детали требуют доступа к слишком многим внутренним деталям класса, чтобы сделать его жизнеспособным для реализации в процессе реализации.