Урок №125. Статические методы класса

  Юрий  | 

  |

  Обновл. 13 Сен 2021  | 

 101103

 ǀ   14 

На предыдущем уроке мы узнали, что статические переменные-члены — это члены, которые принадлежат классу, а не его объектам.

Статические методы

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

В этом случае мы не можем напрямую получить доступ к Anything::s_value из функции main(), так как этот член является private. Обычно, доступ к закрытым членам класса осуществляется через public-методы. Хотя мы могли бы создать обычный метод для получения доступа к s_value, но нам тогда пришлось бы создавать объект этого класса для использования метода! Есть вариант получше: мы можем сделать метод статическим.

Подобно статическим переменным-членам, статические методы не привязаны к какому-либо одному объекту класса. Вот вышеприведенный пример, но уже со статическим методом:

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

Статические методы не имеют указателя *this


У статических методов есть две интересные особенности.

Во-первых, поскольку статические методы не привязаны к объекту, то они не имеют скрытого указателя *this! Здесь есть смысл, так как указатель *this всегда указывает на объект, с которым работает метод. Статические методы могут не работать через объект, поэтому и указатель *this не нужен.

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

Еще один пример

Статические методы можно определять вне тела класса. Это работает так же, как и с обычными методами. Например:

Результат выполнения программы:

The next ID is: 1
The next ID is: 2
The next ID is: 3
The next ID is: 4

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

Предупреждение о классах со всеми статическими членами


Будьте осторожны при написании классов со всеми статическими членами. Хотя такие «чисто статические классы» могут быть полезны, но они также имеют свои недостатки.

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

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

C++ не поддерживает статические конструкторы

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

Если ваша статическая переменная может быть инициализирована напрямую, то конструктор не нужен: вы можете определить статическую переменную-член, даже если она является private. Мы делали это в вышеприведенном примере с s_nextID. Вот еще один пример:

Если для инициализации вашей статической переменной-члена требуется выполнить код (например, цикл), то есть несколько разных способов это сделать. Следующий способ является лучшим из них:

Результат выполнения программы:

o a u i e

При определении статического члена s_initializer вызовется конструктор по умолчанию _nested() (так как s_initializer является объектом класса _nested). Мы можем использовать этот конструктор для инициализации любых статических переменных-членов класса Something. Самое крутое здесь — это то, что весь код инициализации скрыт внутри исходного класса со статическим членом.

Заключение


Статические методы могут использоваться для работы со статическими переменными-членами класса. Для работы с ними не требуется создавать объекты класса.

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

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (327 оценок, среднее: 4,89 из 5)
Загрузка...

Комментариев: 14

  1. Павел:

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

  2. Андрей:

    Зачем писать вне класса

    Ведь внутри класса описано что это вектор типа char.
    Почему недостаточно просто

    ?

    1. Павел:

      Когда мы объявляем статическую переменную-член внутри тела класса, то мы сообщаем компилятору о существовании статической переменной-члене, но не о её определении (аналогией является предварительное объявление). https://ravesli.com/urok-124-staticheskie-peremennye-chleny-klassa/#toc-2
      Аналогично предварительному объявлению:

  3. Анатолий:

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

    1. xshady:

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

  4. Алексей:

    Что это за конструкция и как она работает?

    1. Павел:

      В строке выше

      нам нужно было добраться до статической переменной s_mychars снаружи. Это делается через имя класса Something и оператор разрешения области видимости ::

      Перед этим еще нужно указать тип переменной.

      Теперь же, нам нужно добраться до переменной s_initializer класса Something.

      Это переменная имеет тип _nested.

      _nested является вложенным классом, внутри класса Something.

      Поэтому чтобы добраться до типа переменной s_initializer снаружи, его тоже нужно вызывать через Something::_nested

      После типа пишем саму переменную — Something::s_initializer

  5. Юрий:

    Зачем эта конструкция в последнем примере:

    Это ж тоже самое, что s_mychars = { 'o', 'a', 'u', 'i', 'e' }?

  6. Константин:

    Ещё не сказано, что статическая функция-член не может иметь квалификатор const, причина такая же как и с *this.

  7. Grave18:

    Кстати, а в чем заключается проблема добавления статических конструктов в новых версиях с++?

  8. cybersatori:

    к последнему коду жизнь меня не готовила) минус мозг

  9. Джек:

    Как наследуются статические методы?

    1. Grave18:

      До наследования ещё не дошли)

    2. Константин:

      Отвечаю скорее, для тех, у кого возникнет такой же вопрос при чтении данного урока.

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

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *