Статические члены класса/структуры

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

Члены класса могут быть объявлены с использованием модификатора класса памяти static. Такие члены данных разделяются всеми экземплярами данного класса и хранятся в одном месте. Нестатические члены данных создаются для каждой переменной-объекта класса.

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

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

class_name::variable

где class_name – это имя класса, а variable означает имя члена класса.

Как видите, для обращения к статическому члену класса используется оператор разрешения контекста ::. При обращении к статическому члену внутри методов класса оператор контекста необязателен.

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

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

//+------------------------------------------------------------------+
//| Класс "Анализатор текстов"                                       |
//+------------------------------------------------------------------+
class СParser
  {
public:
   static int        s_words;
   static int        s_symbols;
   //--- конструктор и деструктор
                     CParser(void);
                    ~CParser(void){};
  };
...
//--- инициализация статических членов класса Parser на глобальном уровне
int CParser::s_words=0;
int CParser::s_symbols=0;

Статический член класса можно объявить с ключевым словом const. Такие статические константы должны быть инициализированы на глобальном уровне с ключевым словом const:

//+------------------------------------------------------------------+
//| Класс "Стек" для хранения обрабатываемых данных                  |
//+------------------------------------------------------------------+
class CStack
  {
public:
                     CStack(void);
                    ~CStack(void){};
...
private:
   static const int  s_max_length; // максимальная емкость стека
  };
 
//--- инициализация статической константы класса CStack
const int CStack::s_max_length=1000;

Указатель this #

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

В статических функциях можно обращаться только к статическим членам/методам класса.

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

В MQL5 разрешается использовать функции-члены типа static. Модификатор static должен идти перед возвращаемым типом функции в объявлении внутри класса.

class CStack
  {
public:
   //--- конструктор и деструктор
                     CStack(void){};
                    ~CStack(void){};
   //--- максимальная емкость стека
   static int        Capacity();
private:
   int               m_length;     // количество элементов в стеке
   static const int  s_max_length; // максимальная емкость стека
  };
//+------------------------------------------------------------------+
//| Возвращает максимальную вместимость стека                        |
//+------------------------------------------------------------------+
int CStack::Capacity(void)
  {
   return(s_max_length);
  };
//--- инициализация статической константы класса CStack
const int CStack::s_max_length=1000;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- объявим переменную типа CStack
   CStack stack;
//--- вызываем статический метод объекта
   Print("CStack.s_max_length=",stack.Capacity());
//--- а можно и так вызвать, т.к. метод статический и не требует наличия объекта 
   Print("CStack.s_max_length=",CStack::Capacity());
  }

Метод с модификатором const называется постоянным и не может модифицировать неявные члены своего класса. Объявление постоянных функций класса и постоянных параметров называется контролем постоянства (const-correctness). Благодаря такому контролю можно быть уверенным, что компилятор проследит за неизменностью значений объектов и выдаст ошибку еще на стадии компиляции в случае нарушения.

Модификатор const ставится после списка аргументов внутри объявления класса. Определение вне класса также должно включать модификатор const:

//+------------------------------------------------------------------+
//| Класс "Прямоугольник"                                            |
//+------------------------------------------------------------------+
class CRectangle
  {
private:
   double            m_width;      // ширина  
   double            m_height;     // высота
public:
   //--- конструкторы и деструктор
                     CRectangle(void):m_width(0),m_height(0){};
                     CRectangle(const double w,const double h):m_width(w),m_height(h){};
                    ~CRectangle(void){};
   //--- вычисление площади
   double            Square(voidconst;
   static double     Square(const double w,const double h);// { return(w*h); }
  };
//+------------------------------------------------------------------+
//| Возвращает площадь объекта "Прямоугольник"                       |
//+------------------------------------------------------------------+
double CRectangle::Square(voidconst
  {
   return(Square(m_width,m_height));
  }
//+------------------------------------------------------------------+
//| Возвращает произведение двух переменных                          |
//+------------------------------------------------------------------+
static double CRectangle::Square(const double w,const double h)
  {
   return(w*h);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- создадим прямоугольник rect со сторонами 5 и 6
   CRectangle rect(5,6);
//--- выведем площадь прямоугольника константным методом
   PrintFormat("rect.Square()=%.2f",rect.Square());
//--- выведем произведние чисел с помощью статического метода класса CRectangle
   PrintFormat("CRectangle::Square(2.0,1.5)=%f",CRectangle::Square(2.0,1.5));
  }

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

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

 

Смотри также

Статические переменные, Переменные, Ссылки. Модификатор & и ключевое слово this