Что такое использование частных статических функций-членов? - PullRequest
37 голосов
/ 23 июня 2011

Я смотрел на парсер запросов из примера boost :: asio, и мне было интересно, почему закрытые функции-члены, такие как is_char(), являются static? :

class request_parser
{
  ...
  private:
    static bool is_char(int c);
  ...
};

Используется в функции потребляет , которая не является статической функцией:

boost::tribool request_parser::consume(request& req, char input)
{
  switch (state_)
  {
    case method_start:
    if (!is_char(input) || is_ctl(input) || is_tspecial(input))
    {
      return false;
    }
    ...

Только функции-члены могут вызывать is_char(), и никакая статическая функция-член не вызывает is_char(). Так есть ли причина, по которой эти функции статичны?

Ответы [ 5 ]

63 голосов
/ 23 июня 2011

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

  1. Предоставляет функции доступ к закрытым и защищенным членам любого объекта класса, если объект является статическим или передается функции;
  2. Он связывает функцию с классом аналогично пространству имен.

В этом случае оказывается, что применяется только вторая точка.

15 голосов
/ 23 июня 2011

Так есть ли причина, по которой эти функции являются статическими?

Не- static функции-члены имеют скрытый дополнительный параметр, называемый this.Прохождение этого не является бесплатным, поэтому создание private функции static можно рассматривать как средство оптимизации .
Но это также можно рассматривать каксредство , выражающее ваши требования / дизайн в вашем коде : если эта функция не должна ссылаться на какие-либо данные члена класса, почему она должна быть не static функция-член?

Однако для изменения типа любой функции-члена, public или private, static или нет, потребуется перекомпиляция всех клиентов.Если это необходимо сделать для функции private, которую эти клиенты никогда не смогут использовать, это пустая трата ресурсов.Поэтому я обычно перемещаю как можно больше функций из закрытых частей класса в безымянное пространство имен в файле реализации .

5 голосов
/ 23 июня 2011

Для этого конкретного примера выбор static is_char(), скорее всего, документальный. Цель состоит в том, чтобы убедить вас, что метод is_char() не противоречит конкретному экземпляру класса, но функциональность специфична для самого класса .

Другими словами, делая это static, они говорят, что is_char() - это своего рода функция полезности, которая может использоваться независимо от состояния данного экземпляра. Делая это private, они говорят, что вы (как клиент) не должны пытаться использовать его. Он либо не выполняет то, что вы думаете, либо реализуется очень ограниченным, контролируемым образом.

@ Ответ Марка Рэнсома поднимает вопрос о практическом использовании частной статической функции-члена. В частности, эта функция-член имеет доступ к закрытым и защищенным членам статического объекта или переданного экземпляра экземпляра объекта.

Одним из распространенных применений этого является абстракция реализации pthread в некоторой степени объектно-ориентированным способом. Ваша функция потока должна быть статической, но объявление ее закрытой ограничивает доступ этой функции к классу (для всех, кроме самых определенных). Потоку может быть передан экземпляр класса, в котором он «скрыт», и теперь у него есть доступ для выполнения логики с использованием данных члена объекта.

Упрощенный пример:

[MyWorkerClass.h]
...
public:
    bool createThread();

private:
    int getThisObjectsData();

    pthread_t    myThreadId_;
    static void* myThread( void *arg );
...

[MyWorkerClass.cpp]
...
bool MyWorkerClass::createThread()
{
    ...
    int result =  pthread_create(myThreadId_, 
                                 NULL,
                                 myThread), 
                                 this);
    ...
}

/*static*/ void* MyWorkerClass::myThread( void *arg )
{
    MyWorkerClass* thisObj = (MyWorkerClass*)(arg);
    int someData = thisObj->getThisObjectsData();
}
...
2 голосов
/ 23 июня 2011

Это статично, поскольку не требует доступа ни к каким переменным-членам объектов request_parser.Следовательно, делая ее статической, она разъединяет функцию, поскольку она уменьшает количество состояний, к которым может обращаться функция.

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

0 голосов
/ 23 июня 2011

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

...