Подтвердить что ты не робот

Функции "Помощник" в С++

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

Это заставило меня подумать о том, как лучше всего объединить функции "помощника". Путь Java/С# должен был бы использовать класс статических функций с частным конструктором, например:

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

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

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

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

4b9b3361

Ответ 1

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

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

    например. Я сделал что-то вроде

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

Ответ 2

Случай, когда можно использовать 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;
}

Ответ 3

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

//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

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

Ответ 4

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

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

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

Ответ 5

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

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

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

Ответ 6

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

Использование "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
}

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

Пространства имен больше, чем пакеты. Другой пример можно найти в Bjarne Stroustrup "Язык программирования С++".

В "Специальном выпуске" в 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() ;
}

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

Ответ 7

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