Вспомогательные функции в C++

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

Это заставило меня задуматься о том, как лучше всего сгруппировать «вспомогательные» функции вместе. Способ Java / C# заключался бы в использовании класса статических функций с частным конструктором, например:

class Helper  
{  
private:  
  Helper() { }
public:  
  static int HelperFunc1();  
  static int HelperFunc2();  
};

Однако, будучи C++, вы также можете использовать пространство имен:

namespace Helper  
{  
  int HelperFunc1();  
  int HelperFunc2();  
}

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

Я бы предложил более информативный заголовок для этого вопроса, возможно, что-то вроде: «пространство имен vs. класс для функций« Помощник »в C++»

jwfearn 20.09.2008 22:16
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
30
1
18 706
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Основное преимущество использования пространства имен заключается в том, что вы можете снова открыть его и добавить что-нибудь позже, чего нельзя сделать с классом. Это делает этот подход лучше для слабосвязанных помощников (например, у вас может быть пространство имен Helpers для всей вашей библиотеки, как и весь STL в :: std)

Основное преимущество класса заключается в том, что вы можете вложить его внутри класса, используя его, вы не можете вложить пространство имен в класс. Это делает этот подход более подходящим для тесно связанных помощников.

У вас не будет дополнительных накладных расходов, если они будут в классе по сравнению с пространством имен.

Верно, что вы не можете вложить пространство имен в класс, но вы можете использовать анонимное пространство имен в CPP-файле класса практически с таким же эффектом (или даже именованное пространство имен, вложенное в анонимное). Но хороший ответ!

Drew Hall 20.12.2008 17:34
Ответ принят как подходящий

Накладные расходы не являются проблемой, хотя у пространств имен есть некоторые преимущества.

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

    например Я делал такие вещи, как

    namespace LittleEndianHelper {
       void Function();
    }
    namespace BigEndianHelper {
       void Function();
    }
    
    #if powerpc
       namespace Helper = BigEndianHelper;
    #elif intel
       namespace Helper = LittleEndianHelper;
    #endif
    

Или вы можете сказать #if powerpc \ using BigEndianHelper; \ #else ... Это исключает квалификатор при вызове функции. То, что вы не можете сделать в классе (в глобальном масштабе): Class :: func

jmucchiello 20.12.2008 17:19

Интересное использование для переключения пространства имен "по умолчанию", но с сохранением доступности обеих реализаций.

peterchen 30.12.2008 19:40

@joe, да, но тогда другая реализация больше не доступна. Например. Файлы фотошопа находятся внутри в основном BigEndian (независимо от платформы), вы все равно можете использовать BigEndianHelper в функциях, которые работают с файлами фотошопа, и использовать помощник по платформе в других местах (просто пример;)

Pieter 03.03.2009 13:09

Чтобы добавить к отличному ответу Питера, еще одним преимуществом пространств имен является то, что вы можете пересылать объявления, которые вы поместили в пространство имен где-то еще, особенно структуры ...

//Header a.h
// Lots of big header files, spreading throughout your code
class foo
{
  struct bar {/* ... */);
};

//header b.h
#include a.h // Required, no way around it, pulls in big headers
class b
{
  //...
  DoSomething(foo::bar);
};

И с пространствами имен ...

//Header a.h
// Big header files
namespace foo
{
  struct bar {/* ... */);
}

//header b.h
// Avoid include, instead forward declare 
//  (can put forward declares in a _fwd.h file)
namespace foo
{
  struct bar;
}

class b
{
  //...
  // note that foo:bar must be passed by reference or pointer
  void DoSomething(const foo::bar & o);
};

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

Редактировать от paercebal

Ответ был слишком хорош, чтобы позволить ему умереть из-за ошибки перечисления (см. Комментарии). Я заменил перечисления (которые могут быть объявлены вперед только в C++ 0x, а не в сегодняшнем C++) структурами.

На самом деле вы не можете пересылать объявления перечислений. Прямое объявление перечислений - это расширение Microsoft, поэтому его переносимость не гарантируется.

graham.reeds 17.09.2008 14:23

Я согласен с graham.reeds. вы не можете переслать перечисление, размер которого зависит от фактических значений меток перечисления

ugasoft 18.09.2008 17:52

Правильное перечисление по структуре. +1 в любом случае, потому что это очень веская причина, и это потому, что я слишком много споткнулся о типе кода, использующем классы вместо пространств имен, и был вынужден сделать полное включение вместо прямого объявления.

paercebal 20.12.2008 17:15

Для всех, кого смущают предыдущие комментарии: уже около десяти лет можно пересылать объявления enum. См. здесь.

A. Howells 21.05.2019 17:55

Пространства имен предлагают дополнительное преимущество поиска по Кенигу. Использование вспомогательных классов может сделать ваш код более подробным - обычно вам нужно включать имя вспомогательного класса в вызов.

Еще одно преимущество пространств имен - их удобочитаемость в дальнейшем. С классами вам нужно включать такие слова, как «Помощник», чтобы позже напомнить вам, что конкретный класс не используется для создания объектов.

На практике накладных расходов тоже нет. После компиляции меняется только название, используемое для изменения имени.

Случай, когда можно использовать class (или struct) вместо namespace, - это когда нужен тип, например:

struct C {
  static int f() { return 33; }
};

namespace N {
  int f() { return 9; }
}

template<typename T>
int foo() {
  return T::f();
}

int main() {
  int ret = foo<C>();
//ret += foo<N>(); // compile error: N is a namespace
  return ret;
}

Ого ... Я ДЕЙСТВИТЕЛЬНО верю, что пространства имен лучше классов для такого рода проблем, но ваш пример - ОДИН пример, когда классы имеют ОДНО преимущество перед пространствами имен. +1.

paercebal 20.12.2008 16:46

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

paercebal 20.12.2008 16:47

Я бы заменил «одно преимущество» на «единственное преимущество».

Tom 21.12.2008 05:06

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

Скопировал / обрезал / переработал часть моего ответа из Как правильно использовать пространства имен в C++?.

Использование "использования"

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

struct AAA
{
   void makeSomething() ;
} ;

namespace BBB
{
   void makeSomethingElse() ;
}

void willCompile()
{
   AAA::makeSomething() ;
   BBB::makeSomethingElse() ;
}

void willCompileAgain()
{
   using BBB ;

   makeSomethingElse() ; // This will call BBB::makeSomethingElse()
}

void WONT_COMPILE()
{
   using AAA ; // ERROR : Won't compile

   makeSomething() ; // ERROR : Won't compile
}

Состав пространства имен

Пространства имен - это больше, чем просто пакеты. Другой пример можно найти в книге Бьярна Страуструпа «Язык программирования C++».

В «Специальном выпуске» в 8.2.8 Состав пространства имен он описывает, как можно объединить два пространства имен AAA и BBB в другое, называемое CCC. Таким образом, CCC становится псевдонимом для AAA и BBB:

namespace AAA
{
   void doSomething() ;
}

namespace BBB
{
   void doSomethingElse() ;
}

namespace CCC
{
   using namespace AAA ;
   using namespace BBB ;
}

void doSomethingAgain()
{
   CCC::doSomething() ;
   CCC::doSomethingElse() ;
}

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

Другие вопросы по теме