Права доступа

Для изменения прав доступа к членам класса применяется особый синтаксис (мы с ним уже познакомились в главе про структуры). В любом месте блока, перед описанием членов класса можно вставить модификатор: одно из трех ключевых слов — private, protected, public — и двоеточие.

Все идущие за модификатором члены, пока не встретится другой модификатор, или вплоть до конца класса, получат соответствующее ограничение видимости.

Например, следующая запись идентична предыдущему описанию класса Shape, потому что для классов при отсутствии модификаторов подразумевается режим private:

class Shape
{
private:
   int xy;              // координаты центра
   color backgroundColor// цвет заливки
   ...
};

Если бы мы захотели открыть доступ ко всем полям, то поменяли бы модификатор на public:

class Shape
{
public:
   int xy;              // координаты центра
   ...
};

Но это нарушило бы принцип инкапсуляции, и мы не станем так делать. Вместо этого вставим модификатор protected: он разрешает обращаться к членам из производных классов, но оставляет их скрытыми от внешнего мира. Мы планируем унаследовать от класса Shape несколько других классов фигур, и в них будет нужен доступ к переменным родителя.

class Shape
{
protected:
   int xy;              // координаты центра
   color backgroundColor// цвет заливки
   
public:
   string toString() const
   {
      return (string)x + " " + (string)y;
   }
   
   void draw() { /* заглушка будущего интерфейса рисования */ }
};

Попутно мы сделали обе функции публичными.

Модификаторы могут чередоваться в описании класса произвольным образом и повторяться много раз. Однако в целях улучшения читабельности кода рекомендуется делать по одной секции открытых (public), защищенных (protected) и закрытых (private) членов, причем выдерживать один и тот же их порядок во всех классах проекта.

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

В функции toString, как и в любом методе класса, поля доступны по их именам. Позднее мы познакомимся с возможностью описывать методы как статические: они относятся целиком к классу, а не к экземплярам-объектам, и потому в них нельзя обращаться к полям.

Теперь мы можем вызвать метод toString у переменной-объекта s:

void OnStart()
{
   Shape s;
   Print(s.toString());
}

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

Метод toString — публичный, и потому доступен из внешней по отношению к классу функции OnStart. Если бы мы попытались в OnStart через разыменование "достучаться" до полей s.x или s.y, то получили бы ошибку компиляции "невозможен доступ к защищенному члену класса 'Shape'" ("cannot access protected member declared in class 'Shape'").

Для знатоков C++ отметим, что MQL5 не поддерживает так называемых "друзей" (для остальных поясним, что в C++ можно, при необходимости, составлять своего рода "белый список" сторонних классов и методов, которые имеют расширенные права, хотя и не являются "родственниками").

Запустив программу, мы убедимся, что она выводит пару чисел. Однако значения координат будут случайными. Даже если вам повезет увидеть нули, это не гарантирует, что они появятся при следующем запуске скрипта. Как правило, если в терминале не меняется перечень выполняющихся MQL-программ, повторные запуски любого скрипта приводят к выделению ему одной и той же области памяти, из-за чего может сложиться обманчивое впечатление, что состояние объекта стабильное. На самом деле поля объекта, как и в случае локальных переменных, ничем не инициализируются по умолчанию (см. раздел Инициализация).

Чтобы их проинициализировать применяются специальные функции класса — конструкторы.