Где можно выполнять инициализацию статистической переменной класса
Перейти к содержимому

Где можно выполнять инициализацию статистической переменной класса

Где можно выполнять инициализацию статистической переменной класса

Кроме переменных и методов, которые относятся непосредственно к объекту, C++ позволяет определять переменные и методы, которые относятся непосредственно к классу или иначе говоя статические члены класса. Статические переменные и методы относят в целом ко всему классу. Для их определения используется ключевое слово static .

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

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

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

Также важно, что если класс содержит статические переменные, то они должны быть дополнительно определены вне класса:

Присваивать начальное значение переменной необязательно.

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

Консольный вывод программы:

Также нередко в классах используют статические константы. Например, сделаем в классе Account переменную rate константой:

В отличие от статических переменных статические константы не нужно дополнительно определять вне класса.

Пока смерть не разлучит нас или всё о 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, мы можем увидеть следующий результат программы:

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

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

Статические функции пришли в С++ из С. По умолчанию все функции в С глобальные и, если вы захотите создать две функции с одинаковым именем в двух разных .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 , которое может использоваться при объявлении член-данных и член-функций.

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

Обращение к статическому элементу осуществляется с помощью оператора разрешения контекста и имени класса:
ИмяКласса :: ИмяЭлемента
Если x – статическое член-данное класса cl, то к нему можно обращаться как
cl::x
При этом не имеет значения количество объектов класса cl.

Аналогично можно обращаться к статической член-функции:

Статические член-данные (или поля) класса можно рассматривать как глобальную переменную класса. Но в отличие от обычных глобальных переменных на статические члены распространяются правила видимости private и public . Поместив статическую переменную в часть private , можно ограничить ее использование.

Объявление статического члена в объявлении класса не является определением, то есть это объявление статического члена не обеспечивает распределения памяти и инициализацию.

Инициализация статических полей

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

Результат выполнения
Статические члены класса

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

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