- •Ооп: Лекция 5. Вспомогательные средства для создания классов
- •Статические переменные-члены
- •Статические функции-члены
- •Приемы применения статических членов — разделяемый ресурс
- •Приемы применения статических членов — Factory Method
- •Приемы применения статических членов — Singleton
- •Физическое и логическое постоянство
- •Указатели на члены
- •Полные примеры из лекции
Статические функции-члены
Помимо статических переменных-членов, классы могут также содержать статические функции-члены. Аналогично переменным, задачей таких функций является инкапсуляция некоторых действий, имеющих отношение к классу, а не к его объектам. Статические и нестатические функции-члены, так же как и переменные, объединяет общая область видимости, ограниченная классом, а также одинаковое влияние спецификаторов доступа.
Синтаксически статические и нестатические функции-члены различаются по наличию ключевого слова static в объявлении. Если реализация функции осуществляется за пределами класса, модификатор static для тела функции повторно указывать не нужно. Обращение к статическим функциям-членам за пределами класса осуществляется идентично статическим переменным-членам — предпочтительно через имя класса + оператор разрешения области видимости (::), однако возможно получение доступа и через объект.
Поскольку статические функции-члены не имеют отношения к конкретным объектам родительского класса, в отличие от нестатических функций-членов, статическим не передается неявный указатель this. Количество явно записанных программистом формальных аргументов всегда соответствует количеству фактически передаваемых при вызове. С точки зрения низкоуровневой реализации компилятором, статические функции-члены мало чем отличаются от глобальных функций. Единственной разницей является влияние имени класса на результирующие сигнатуры функций, что необходимо для реализации компоновки с учетом правил областей видимости.
Из отсутствия неявно передаваемого указателя this в статических функциях-членах вытекает ряд ограничений на содержащийся в их телах программный код:
Нельзя напрямую по имени обращаться к нестатическим переменным-членам класса, поскольку нет объекта, через который можно было бы получить к ним доступ.
Нельзя напрямую по имени вызывать нестатические функции-члены, поскольку нет объекта, указатель на который передавать в качестве this при вызове.
Нельзя совмещать модификаторы static и const, поскольку модификатор const для функций-членов влияет на тип неявно передаваемого указателя this, которого статические функции-члены не получают.
В то же время, любая нестатическая функция-член класса может в произвольный момент обратиться к любой статической функции-члену или к статической переменной-члену, поскольку они доступны для любого объекта данного класса.
В приведенном ниже примере используются как статическая переменная-член, так и статическая функция-член (по сути, функция играет роль статического варианта метода-геттера). Имеется класс, описывающий оценку студента по некоторой дисциплине. В статической переменной-члене ms_MaxMark сохраняется максимальная оценка, которую получал любой из экземпляров, автоматически корректируемая в конструкторе объектов. А при помощи статической функции-члена GetMaxMark определенный на текущий момент максимум оценки возвращается клиентскому коду:
student.hpp
#ifndef _STUDENT_HPP_
#define _STUDENT_HPP_
class Student
{
// Обычные (нестатические) переменные-члены (храним в объекте)
const char * m_LastName;
const int m_Mark;
// Статическая переменная-член (храним независимо от объектов в сегменте данных).
// Содержит текущую накопленную максимальную оценку студентов.
static int ms_MaxMark;
public:
// Объявление конструктора
Student ( const char * _lastName, int _mark );
// Статическая функция-член: возвращает текущую накопленную максимальную оценку
static int GetMaxMark ();
};
// Реализация статической функции-члена.
// Модификатор static в выносной реализации не указывается.
inline int Student::GetMaxMark ()
{
return ms_MaxMark; // Доступ к этой переменной разрешен.
// Обращаться к m_LastName или m_Mark здесь нельзя
}
#endif // _STUDENT_HPP_
student.cpp
#include “student.hpp”
// Определение статической переменной-члена, значение 0 по умолчанию
int Student::ms_MaxMark;
// Реализация конструктора
Student::Student ( const char * _lastName, int _mark )
: m_LastName( _lastName ),
m_Mark( _mark )
{
// Обновляем максимальную оценку, если новая оценка выше
if ( m_Mark > ms_MaxMark )
// Конструктор является обычной нестатической функцией-членом)
// Соответственно, может получать доступ к любой переменной класса.
ms_MaxMark = m_Mark;
}
test.cpp
#include “student.hpp”
#include <iostream>
int main ()
{
// Создаем несколько экземпляров класса с различными оценками
Student s1( "Ivanov", 75 );
Student s2( "Petrov", 80 );
Student s3( "Sidorov", 60 );
// Выводим накопленный максимум через вызов статической функции-члена
std::cout << "Maximum mark among students: "
<< Student::GetMaxMark() // this здесь не передается
<< std::endl;
// Вызов через любой объект также возможен, tnis не передается
// ... << s1.GetMaxMark() ... <<
}
Вывод программы на консоль будет содержать следующее:
Maximum mark among students: 80
