Разница между вариантами 2 и 3 заключается в том, что во втором случае функция будет внутренней по отношению к единице перевода. Если функция определена только в cpp, это должна быть опция (которая приблизительно эквивалентна безымянному пространству имен - что является четвертым вариантом для рассмотрения, опять же примерно эквивалентным 3).
Если функция будет использоваться различными единицами перевода, вам следует перейти к варианту 2. Функция будет скомпилирована один раз (если вы не пометите ее как inline
и не предоставите определение в заголовке), тогда как с опцией 3 компилятор создаст свою внутреннюю копию в каждой единице перевода.
Что касается варианта 1, я бы его избежал. В Java или C # вы вынуждены использовать классы повсюду, и в итоге вы получаете служебные классы , когда операции плохо сопоставляются с парадигмой объекта. В C ++, с другой стороны, вы можете предоставлять эти операции в виде автономных функций, и нет необходимости добавлять дополнительный слой. Если вы выбрали служебный класс , не забудьте отключить создание объектов.
Будут ли функции на уровне класса или пространства имен, это повлияет на поиск, и это повлияет на пользовательский код. Статические функции-члены всегда должны указывать имя класса, если только вы не находитесь внутри области действия класса, в то время как существуют разные способы ввода функций пространства имен в область действия. В качестве иллюстративного примера рассмотрим набор математических вспомогательных функций и вызывающий код:
double do_maths( double x ) {
using namespace math;
return my_sqrt( x ) * cube_root(x);
}
// alternatively with an utility class:
double do_maths( double x ) {
return math::my_sqrt(x) * math::cube_root(x);
}
То, что вам легче читать, - это другая история, но я предпочитаю первую: в функции я могу выбрать пространство имен, а затем просто сосредоточиться на операциях и игнорировать проблемы поиска.