Использование «статического» ключевого слова для ограничения доступа в функциях-членах C ++ - PullRequest
5 голосов
/ 05 октября 2010

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

Например, обычной практикой является то, что вы знаете, что у функции будут аргументы, которые не следует изменять, чтобы просто пометить эти константы. e.g.:

bool My_Class::do_stuff(const int not_to_be_changed_1,
                        std::vector<int> const * const not_to_be_changed_2)
{
  //I can't change my int var, my vector pointer, or the ints inside it.
}

Так допустимо ли использование статических функций-членов для ограничения доступа. Например, допустим, у вас есть функция

void My_Class::print_error(const unsigned int error_no) {
  switch (error_no) {
    case 1:
      std::cout << "Bad read on..." << std::endl;
      break;
    //...
    default:
      break;
  }
}

Ну, здесь мы не будем обращаться к переменным-членам класса. Так что, если я изменил функцию на:

static void My_Class::print_error(const unsigned int error_no) {
  switch (error_no) {
    case 1:
      std::cout << "Bad read on..." << std::endl;
      break;
    //...
    default:
      break;
  }
}

Теперь я получил бы ошибку, если бы случайно попытался получить доступ к одному из моих личных переменных и т. Д. (Если я не передам себе экземпляр моего класса, который был бы целенаправленным ^ _ ^!)

Является ли это допустимой техникой, похожей на проактивное создание аргументов, которые не должны быть изменены константами?

Какие минусы у него могут быть с точки зрения эффективности или использования?

Моя главная причина спрашивать, что большинство «статических» уроков, которые я прочитал, не упоминало о его использовании таким образом, поэтому мне было интересно, есть ли веская причина, почему нет, учитывая, что это кажется полезным инструментом .


Редактировать 1 : еще одно логическое обоснование этого использования:

У меня есть функция print_error, как описано выше. Я мог бы использовать пространство имен:

namespace MY_SPACE {
   static void print_error(...) {
      ...
   } 

   class My_Class {
      ....
      void a(void)
   }
}

Но это боль, потому что теперь мне нужно удлинить ВСЕ мои объявления вар, то есть

MY_SPACE::My_Class class_1;

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

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

//can't change pointer to list directly
void My_Class::print_error(std::vector<int> const * error_code_list) {...}

//can't change pointer to list or list members directly
void My_Class::print_error(std::vector<int> const * const error_code_list) {...}

//can't change pointer to list or list members directly, access
//non-const member vars/functions
void My_Class::print_error(std::vector<int> const * const error_code_list) const {...}

//can't change pointer to list or list members directly, access
//non-static member vars/functions
static void My_Class::print_error(std::vector<int> const * const error_code_list) {...}

//can't change pointer to list or list members directly, access
//member vars/functions that are not BOTH static and const
static void My_Class::print_error(std::vector<int> const * const error_code_list) const {...}

Конечно, это немного нетипично, но в меньшей степени, поэтому используются константные функции и константные переменные. Я видел много примеров, когда люди могли бы использовать функцию const, но это не так. Все же некоторые люди думают, что это хорошая идея. Я знаю многих начинающих программистов на С ++, которые не понимали бы значения константной или статической функции. Точно так же многие поняли бы и то и другое.

Так почему некоторые люди так категорически против использования этого в качестве механизма контроля доступа, если язык / спецификация предусматривает его использование как таковое, так же, как это происходит с функциями const и т. Д .?

Ответы [ 4 ]

5 голосов
/ 05 октября 2010

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

Статические элементы обычно используются экономно, например, заводские методы. Вы создадите ситуацию, которая заставит следующего человека, работающего с вашим кодом, перейти к «WTF ???»

3 голосов
/ 05 октября 2010

Не делай этого. Использование static в качестве механизма контроля доступа - варварская мерзость.

Одна из причин не делать этого, потому что это странно. Программистам по техническому обслуживанию будет трудно понять ваш код, потому что он такой странный. Поддерживаемый код - это хороший код. Каждый получает const методы. Никто не получает static-as-const. Лучшая документация для вашего кода - сам код. Самодокументируемый код - это цель, к которой вы должны стремиться. Не так, что вам не нужно писать комментарии, но чтобы они не должны были читать их. Потому что ты знаешь, что они все равно не пойдут.

Другая причина не делать этого - то, что вы никогда не знаете, что принесет будущее. Вашему методу print_error, описанному выше, не требуется доступ к состоянию класса - сейчас. Но я вижу, как это может понадобиться. Предположим, ваш класс является оберткой вокруг сокета UDP. Где-то в середине сеанса другой конец захлопывает дверь. Ты хочешь знать почему. Последние сообщения, которые вы отправили или получили, могут содержать подсказку. Вы не должны бросить это? Для этого вам нужно государство.

Ложная причина сделать это потому, что он обеспечивает контроль доступа членов. Да, это так, но механизмы для этого уже есть. Предположим, вы пишете функцию, которую хотите быть уверены, что она не изменит состояние объекта. Например, print_error не должен изменять состояние объекта. Так что сделайте метод const:

class MyClass
{
public:
  void print_error(const unsigned int error_no) const;
};

...

void MyClass::print_error(const unsigned int error_no) const
{
  // do stuff
}

print_error - это метод const, означающий, что указатель this равен const. Вы не можете изменить ни одного не mutable члена, и вы не можете вызвать любые не const методы. Разве это не то, что вы хотите?

1 голос
/ 05 октября 2010

Статические функции-члены следует использовать, когда они имеют отношение к классу, но не работают с экземпляром класса.

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

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

1 голос
/ 05 октября 2010

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

В частности, единственное различие между статическим методом-членом и функцией-другом состоит в том, что пространства имен различаются, у статического члена есть пространство имен ::className::methodName, а для функции-друга просто ::friendFunctionName. Они оба работают одинаково.

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

Итак, вопрос в том, принадлежит ли функция как " part " класса? если так, используйте статический метод. если нет, поместите метод в глобальную область и сделайте его другом, если ему может понадобиться доступ к закрытым переменным-членам (или нет, если это не так)

...