Что такое статический способ

Содержание
  1. NEWOBJ.ru → Введение в ООП с примерами на C# →
  2. 2.5. Статические методы и поля
  3. § 24. Статические методы. Иногда методу класса не требуется доступ к состоянию объекта. Так, в рассмотренном в главе 2.1 примере расчета площади треугольника, метод расчета SquareGeron не использует поля класса и, соответственно, доступ к переменной this ему не нужен. То есть метод имеет доступ к заведомо не нужным для его работы данным. Чтобы ограничить доступ такого рода методов к полям объекта используют статические методы.
  4. § 25. Статические поля. Аналогично тому, как статический метод не привязан к объекту, мы можем объявить статическое поле, не являющееся частью никакого объекта, которое будет создаваться в одном экземпляре и будет доступно из любого объекта класса или через имя класса.
  5. Вопросы и задания
  6. Пока смерть не разлучит нас или всё о static в C++
  7. Что такое static?
  8. Где используется?
  9. Статические переменные внутри функции
  10. Статические объекты класса
  11. Статические члены класса
  12. Статические функции
  13. Статические функции-члены класса (методы)
  14. Заключение

NEWOBJ.ru → Введение в ООП с примерами на C# →

2.5. Статические методы и поля

2.5. Статические методы и поля

§ 24. Статические методы. Иногда методу класса не требуется доступ к состоянию объекта. Так, в рассмотренном в главе 2.1 примере расчета площади треугольника, метод расчета SquareGeron не использует поля класса и, соответственно, доступ к переменной this ему не нужен. То есть метод имеет доступ к заведомо не нужным для его работы данным. Чтобы ограничить доступ такого рода методов к полям объекта используют статические методы.

Статический метод ( static ) класса – метод, не имеющий доступа к состоянию (полям) объекта, то есть к переменной this .

Для объявления статического метода используется ключевое слово static :

Статический метод может быть вызван как через экземпляр класса, так и через имя класса. Например, из методов класса Triangle мы можем обратиться к статическому методу SquareGeron следующими способами:

Аналогично, извне класса, при условии, что мы сделаем метод SquareGeron открытым:

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

Слово «статический» используется в том смысле, что статические методы не относятся к динамике объекта, не используют и не меняют его состояния.

Вспомним, что мы уже использовали статический метод для вычисления квадратного корня Math.Sqrt . Класс System.Math реализует в виде статических методов и другие математические функции. Однако есть множество причин, почему в большинстве случаев следует избегать использования статических методов.

Программисты, не имеющие опыта ООП, часто начинают широко использовать статические методы как способ программировать на объектно-ориентированном языке в процедурном стиле. Действительно, для статических методов их класс – лишь способ синтаксической группировки. Более того, использование статических методов – это всегда в некотором смысле отход от ООП, так как он делает невозможным использование всех ключевых элементов объектно-ориентированного программирования: абстрактных типов данных, наследования, полиморфизма. Сформулируем следующее правило: в первом приближении статическими следует делать только 1) небольшие 2) вспомогательные 3) закрытые ( private ) методы класса. Практически всегда методы, не удовлетворяющие приведенному правилу и не обращающиеся к полям объекта, можно и нужно вынести в отдельный класс. Например, если бы метод SquareGeron был большим, то следовало бы создать класс SquareGeronCalculator и создать там открытый метод Calc .

§ 25. Статические поля. Аналогично тому, как статический метод не привязан к объекту, мы можем объявить статическое поле, не являющееся частью никакого объекта, которое будет создаваться в одном экземпляре и будет доступно из любого объекта класса или через имя класса.

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

Экземпляр статической переменной создается автоматически до первого ее использования (когда именно – не регламентируется), а при создании экземпляров класса память для статических переменных не выделяется. Таким образом, в приведенном примере в некоторый момент времени после запуска приложения и до вызова команды увеличения значения newCount будет создан ровно один экземпляр этой переменной, а каждый создаваемый объект Point будет увеличивать ее значение в своем конструкторе.

Читайте также:  Способы транспортировки пострадавшего при ранениях

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

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

Тем не менее, статические поля, как и статические методы, используются достаточно широко. Рассмотрим следующий типичный пример.

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

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

Такое решение лучше, но оно все еще позволяет нам передать в метод Authorize произвольную строку, не используя класс Feature . Проанализируйте следующий код:

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

Мы можем пойти еще дальше, сохраняя в классе ACL не массив строк, а массив объектов Features :

Такое решение делает безопасным не только передачу параметра в Authorize , но и формирование списка currentUserAllowedFeatures , который теперь также гарантированно не будет содержать произвольных строк.

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

Вопросы и задания

Что такое статические методы, статические поля?

Верно ли говорить о статических классах или статических объектов? В чем их отличие (если верно) от неизменяемых классов и объектов?

Статический метод не имеет доступ к полям объекта, но имеет ли он доступ к полям объекта того же класса, переданного в параметрах этого метода?

В каком порядке следует использовать ключевые слова public/private и static ?

Сравните следующие поля класса:

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

Статические поля и методы часто применяются для реализации объектов-одиночек 35 . Объект-одиночка ( singleton ) – объект, который должен существовать в программе в одном экземпляре. К примеру, это может быть объект, хранящий глобальные параметры приложения. Разберите следующие реализации:

Объясните, почему вторая реализация лучше? Почему во втором варианте используется закрытый ( private ) конструктор? Почему не используется ключевое слово readonly для поля singleton ?

* Объясните почему использование newCount++ , вместо метода Interlocked.Increment может привести к ошибкам (неверном подсчету).

* Изучите механизм перечислений в C# ( enum ).

35. Отметим попутно, что шаблон «одиночка» в современной практике часто стремятся заменять на шаблон «инверсии управления».↩︎

Источник

Пока смерть не разлучит нас или всё о static в C++

Всем привет. На одном из код-ревью я столкнулся с мыслью, что многие, а чего скрывать и я сам, не то чтобы хорошо понимаем когда нужно использовать ключевое слова static. В данной статье я хотел бы поделиться своими знаниями и информацией по поводу ключевого слова static. Статья будет полезна как начинающим программистам, так и людям, работающим с языком С++. Для понимания статьи у вас должны быть знания о процессе сборки проектов и владение языком С/С++ на базовом уровне. Кстати, static используется не только в С++, но и в С. В этой статье я буду говорить о С++, но имейте в виду, что всё то, что не связано с объектами и классами, в основном применимо и к языку С.

Читайте также:  Способы заплакать за минуту

Что такое static?

Static — это ключевое слово в C++, используемое для придания элементу особых характеристик. Для статических элементов выделение памяти происходит только один раз и существуют эти элементы до завершения программы. Хранятся все эти элементы не в heap и не на stack, а в специальных сегментах памяти, которые называются .data и .bss (зависит от того инициализированы статические данные или нет). На картинке ниже показан типичный макет программной памяти.

Где используется?

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

А теперь я постараюсь детально описать все то, что изображено на схеме. Поехали!

Статические переменные внутри функции

Статические переменные при использовании внутри функции инициализируются только один раз, а затем они сохраняют свое значение. Эти статические переменные хранятся в статической области памяти (.data или .bss), а не в стеке, что позволяет хранить и использовать значение переменной на протяжении всей жизни программы. Давайте рассмотрим две почти одинаковые программы и их поведение. Отличие в них только в том, что одна использует статическую переменную, а вторая нет.

Если не использовать static в строке 4, выделение памяти и инициализация переменной count происходит при каждом вызове функции counter(), и уничтожается каждый раз, когда функция завершается. Но если мы сделаем переменную статической, после инициализации (при первом вызове функции counter()) область видимости count будет до конца функции main(), и переменная будет хранить свое значение между вызовами функции counter().

Статические объекты класса

Статический объект класса имеет такие же свойства как и обычная статическая переменная, описанная выше, т.е. хранится в .data или .bss сегменте памяти, создается на старте и уничтожается при завершении программы, и инициализируется только один раз. Инициализация объекта происходит, как и обычно — через конструктор класса. Рассмотрим пример со статическим объектом класса.

В строке 3 мы создаем класс Base с конструктором (строка 5) и деструктором (строка 8). При вызове конструктора либо деструктора мы выводим название метода класса в консоль. В строке 14 мы создаем статический объект obj класса Base. Создание этого статического объекта будет происходить только при первом вызове функции foo() в строке 18.

Из-за того, что объект статический, деструктор вызывается не при выходе из функции foo() в строке 15, а только при завершении программы, т.к. статический объект разрушается при завершении программы. Ниже приведен пример той же программы, за исключением того, что наш объект нестатический.

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

Статические члены класса

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

В нашем примере мы создали класс А (строка 3) и класс В (строка 9) со статическими членами класса (строка 15). Мы предполагаем, что при создании объекта b в строке 19 будет создан объект a в строке 15. Так бы и произошло, если бы мы использовали нестатические члены класса. Но вывод программы будет следующим:

Причиной такого поведения является то, что статические члены класса не инициализируются с помощью конструктора, поскольку они не зависят от инициализации объекта. Т.е. в строке 15 мы только объявляем объект, а не определяем его, так как определение должно происходить вне класса с помощью оператора разрешения области видимости (::). Давайте определим члены класса B.

Теперь, после того как мы определили наш статический член класса в строке 18, мы можем увидеть следующий результат программы:

Constructor A
Constructor B
Destructor B
Destructor A

Нужно помнить, что член класса будет один для всех экземпляров класса B, т.е. если мы создали три объекта класса B, то конструктор статического члена класса будет вызван только один раз. Вот пример того, о чем я говорю:

Constructor A
Constructor B1
Constructor B2
Constructor B3
Destructor B3
Destructor B2
Destructor B1
Destructor A

Статические функции

Статические функции пришли в С++ из С. По умолчанию все функции в С глобальные и, если вы захотите создать две функции с одинаковым именем в двух разных .c(.cpp) файлах одного проекта, то получите ошибку о том, что данная функция уже определена (fatal error LNK1169: one or more multiply defined symbols found). Ниже приведен листинг трех файлов одной программы.

Читайте также:  Солим боровики горячим способом

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

В этом случае вы говорите компилятору, что доступ к статическим функциям ограничен файлом, в котором они объявлены. И он имеет доступ только к функции sum() из math.cpp файла. Таким образом, используя static для функции, мы можем ограничить область видимости этой функции, и данная функция не будет видна в других файлах, если, конечно, это не заголовочный файл (.h).

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

Статические функции-члены класса (методы)

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

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

Давайте рассмотрим следующий пример:

В классе A в строке 8 у нас есть статическая функция-член foo(). В строке 14, мы вызываем функцию используя имя класса и оператор разрешения области видимости и получаем следующий результат программы:

Из вывода видно, что никакого создания объекта нет и конструктор/деструктор не вызывается.

Если бы метод foo() был бы нестатическим, то компилятор выдал бы ошибку на выражение в строке 14, т.к. нужно создать объект для того, чтобы получить доступ к его нестатическим методам.

Заключение

В одной статье в интернете я нашел совет от автора – «Используйте static везде, где только можно». Я хотел бы написать, почему так делать не стоит, а стоит использовать только в случае необходимости.

  • Статические переменные медленнее, чем нестатические переменные. Для того, чтобы обратиться к статической переменной, нам нужно сделать несколько дополнительных действий, таких как переход в другой сегмент памяти и проверка инициализации переменной. Чаще всего, быстрее выделить локальную переменную на стеке, чем делать дополнительные действия по использованию статической переменной.
  • Если вы используете многопоточность, то здесь вы должны быть крайне осторожными, т.к. возможна ситуация, когда два и более потока захотят писать в одну статическую переменную. Если вы будете использовать нестатические переменные в функциях, то избежите подобного, т.к. для каждого потока будет создана собственная нестатическая переменная.
  • Ключевое слово static является неотъемлемой частью порождающего шаблона проектирования Singleton, который гарантирует, что будет создан только один экземпляр этого класса. В реализации этого паттерна используется и статический объект, и статическая функция-член. На практике вы можете использовать Singleton для создания объекта трейсера, логгера или любого другого объекта, который должен быть один на всё ваше приложение.
  • Иногда для того, чтобы функция отработала только один раз без хранения предыдущего состояния где-то в объекте, используют статические переменные. Пример вы можете посмотреть в разделе «Статические переменные внутри функции». Но это не очень хороший подход, и может привести к долгим часам поиска ошибки, если вы используете многопоточность.
  • На практике, программисты C++ часто используют статические функции-члены как альтернативу обычным функциям, которые не требуют создания объекта для выполнения ее.

Надеюсь, вам понравилась моя статья о ключевом слове static в языке C++. Буду рад любой критике и советам. Всем спасибо!

Источник

Оцените статью
Разные способы