Вопросы по ООП в MQL5 - страница 96

 
class A
{
private:
   int _value;
public:
  void set(const int value)      { _value = value;    }
  int  get()                     { return(_value);    }
  template<typename Type>
  static void set(Type &a, const int value){ ((A*)&a)._value = value;  }
  template<typename Type>
  static int get(Type &a) { return ((A*)&a)._value;  }
};

class B: private A
{
public:
   void set(int a) {A::set(this,a);}
   int get() {return A::get(this);}
};

void OnStart()
{  
   B b;
   b.set(77);
   Print(b.get());
}

ИМХО, но так красивее.

 
Vladimir Simakov:

ИМХО, но так красивее.

у меня чисто теоретические вопросы, сомневаюсь, что имеют практическое применение

Спасибо! красивый код!

 

как сделать чтобы в новом классе отображались глобальные подсказки?

глобал -                                                в классе - 

 
Vladislav Boyko #:

Я говорю о взаимном включении, пример которого обсуждался на видео. Когда Bar.mqh включает Foo.mqh, а Foo.mqh включает Bar.mqh. В таком случае должна быть ошибка компиляции типа "function already defined". Если ошибок компиляции нет, то компилятор смог обеспечить только единократное включение каждого файла в итоговый код.

А можете доходчиво объяснить код из учебника, после таких слов

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

Я смотрел на всё это и ничего не понимая просто закрыл не дочитав до конца…

Учебник по MQL5: Объектно-Ориентированное Программирование / Классы и интерфейсы / Указатели
Учебник по MQL5: Объектно-Ориентированное Программирование / Классы и интерфейсы / Указатели
  • www.mql5.com
Как мы уже говорили в разделе Определение класса , указатели в MQL5 — это некие дескрипторы (уникальные номера) объектов, а не адреса в памяти, как...
 
Alexey Viktorov #:

А можете доходчиво объяснить код из учебника, после таких слов

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

Я смотрел на всё это и ничего не понимая просто закрыл не дочитав до конца…

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

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


Типа условимся считать, что экземпляры класса Element разрешено создавать только классу Manager (на самом деле, ничего не мешает создать отдельно экземпляр Element не используя интерфейс класса Manager).

А Element должен уметь общаться с менеджером, который его создал. То есть, просто вызывать метод того менеджера, передавая ему какую-то информацию. Что бы вызывать метод менеджера элементу нужен указатель на менеджер, вот он:

class Manager;

class Element
  {
   Manager* owner;
  }

Как получить указатель на создателя? Ну пускай создатель передает указатель на себя когда создает экземпляр элемента:

class Element
  {
   Manager* owner;
public:
            Element(Manager &t) : owner(&t) { }
  }

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

class Element
  {
   Manager* owner;
public:
            Element(Manager &t);
  };

Element::Element(Manager &t)
  {
   owner = &t;
  }

Можно переписать тело конструктора более очевидным (для начинающих) образом:

Element::Element(Manager &t)
  {
   owner = GetPointer(t);
  }

Еще упростим - уберем преобразование ссылки в указатель, пускай сразу указатель тот менеджер передает:

class Element
  {
   Manager* owner;
public:
            Element(Manager *t);
  };

Element::Element(Manager *t)
  {
   owner = t;
  }

Зная указатель, элемент может вызывать методы менеджера. Добавим менеджеру метод, в который можно звонить (пускай он принимает строку, что бы не заморачиваться) и добавим элементу имя, что бы различать экземпляры.

class Manager;

class Element
  {
   Manager* owner;
   string   name;
public:
            Element(Manager *t, string a_name);
  };

Element::Element(Manager *t, string a_name)
  {
   owner = t;
   name = a_name;
  }

class Manager
  {
public:
   void call(string text) { Print(text); }
  };

Добавим менеджеру метод для создания экземпляров класса Element (нужно же хоть как-то обосновать существование менеджера). Не хочу делать массив как в книжке, пускай менеджер просто возвращает указатель на соданный экземпляр.

class Manager
  {
public:
   void     call(string text)                 { Print(text);                                        }
   Element* createElement(string elementName) { return(new Element(GetPointer(this), elementName)); }
  };

Менеджеру тоже дадим имя, так как если менеджер будет только один, то в нем нет никакого смысла.

class Manager
  {
private:
   string   name;
public:
   void     call(string text)                 { Print(text);                                        }
   Element* createElement(string elementName) { return(new Element(GetPointer(this), elementName)); }
            Manager(string a_name)            { name = a_name;                                      }
  };

Теперь, когда есть указатель на менеджера и у менеджера есть метод, пускай элемент его вызывает. Например, когда вызывается метод work(). Пускай хоть код еще какой-нибудь передается.

class Element
  {
   Manager* owner;
   string   name;
public:
   void     work(int code) { owner.call("Это " + name + ". Меня заставляют работать, код " + (string)code); }
            Element(Manager *t, string a_name);
  };
 
Vladislav Boyko #:

Ну и собираем в кучу всю эту сомнительную ерунду:

class Manager;

class Element
  {
   Manager* owner;
   string   name;
public:
   void     work(int code) { owner.call("Это " + name + ". Меня заставляют работать, код " + (string)code); }
            Element(Manager *t, string a_name);
  };

Element::Element(Manager *t, string a_name)
  {
   owner = t;
   name = a_name;
  }

class Manager
  {
private:
   string   name;
public:
   void     call(string text)                 { PrintFormat("Менеджер %s получил сообщение: \"%s\"", name, text); }
   Element* createElement(string elementName) { return(new Element(GetPointer(this), elementName));               }
            Manager(string a_name)            { name = a_name;                                                    }
  };

void OnStart()
  {
   // 2 разных менеджера
   Manager anton("Антон");
   Manager egor("Егор");
   // Тут будут указатели на элементы обоих менеджеров
   Element* elements[4];
   // Создает Антон
   elements[0] = anton.createElement("Витя");
   elements[1] = anton.createElement("Эдик");
   // Создает Егор
   elements[2] = egor.createElement("Валера");
   elements[3] = egor.createElement("Толик");
   // Заставляем работать всех
   for(int i = ArraySize(elements) - 1; i >= 0; i--)
      elements[i].work(10 + i);
   //---
   for(int i = ArraySize(elements) - 1; i >= 0; i--)
      delete elements[i];
  }


 
Vladislav Boyko #:

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

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


Типа условимся считать, что экземпляры класса Element разрешено создавать только классу Manager (на самом деле, ничего не мешает создать отдельно экземпляр Element не используя интерфейс класса Manager).

А Element должен уметь общаться с менеджером, который его создал. То есть, просто вызывать метод того менеджера, передавая ему какую-то информацию. Что бы вызывать метод менеджера элементу нужен указатель на менеджер, вот он:

Как получить указатель на создателя? Ну пускай создатель передает указатель на себя когда создает экземпляр элемента:

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

Можно переписать тело конструктора более очевидным (для начинающих) образом:

Еще упростим - уберем преобразование ссылки в указатель, пускай сразу указатель тот менеджер передает:

Зная указатель, элемент может вызывать методы менеджера. Добавим менеджеру метод, в который можно звонить (пускай он принимает строку, что бы не заморачиваться) и добавим элементу имя, что бы различать экземпляры.

Добавим менеджеру метод для создания экземпляров класса Element (нужно же хоть как-то обосновать существование менеджера). Не хочу делать массив как в книжке, пускай менеджер просто возвращает указатель на соданный экземпляр.

Менеджеру тоже дадим имя, так как если менеджер будет только один, то в нем нет никакого смысла.

Теперь, когда есть указатель на менеджера и у менеджера есть метод, пускай элемент его вызывает. Например, когда вызывается метод work(). Пускай хоть код еще какой-нибудь передается.

Vladislav Boyko #:

Ну и собираем в кучу всю эту сомнительную ерунду:

Большое человеческое спасибо. Чуток стало почти понятно. То-есть это можно применить как замену списку объектов?

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

 
Vladislav Boyko #:

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

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


Типа условимся считать, что экземпляры класса Element разрешено создавать только классу Manager (на самом деле, ничего не мешает создать отдельно экземпляр Element не используя интерфейс класса Manager).

А Element должен уметь общаться с менеджером, который его создал. То есть, просто вызывать метод того менеджера, передавая ему какую-то информацию. Что бы вызывать метод менеджера элементу нужен указатель на менеджер, вот он:

Как получить указатель на создателя? Ну пускай создатель передает указатель на себя когда создает экземпляр элемента:

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

Можно переписать тело конструктора более очевидным (для начинающих) образом:

Еще упростим - уберем преобразование ссылки в указатель, пускай сразу указатель тот менеджер передает:

Зная указатель, элемент может вызывать методы менеджера. Добавим менеджеру метод, в который можно звонить (пускай он принимает строку, что бы не заморачиваться) и добавим элементу имя, что бы различать экземпляры.

Добавим менеджеру метод для создания экземпляров класса Element (нужно же хоть как-то обосновать существование менеджера). Не хочу делать массив как в книжке, пускай менеджер просто возвращает указатель на соданный экземпляр.

Менеджеру тоже дадим имя, так как если менеджер будет только один, то в нем нет никакого смысла.

Теперь, когда есть указатель на менеджера и у менеджера есть метод, пускай элемент его вызывает. Например, когда вызывается метод work(). Пускай хоть код еще какой-нибудь передается.

Пример в книге не абстрактный, а самый простой и практичный - сообщение группой расчетных алгоритмов процента выполнения конкретной задачи в планировщик задач. Это сплошь и рядом встречается.

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

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

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

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

 

Начинается как в автосервисе…

— Кто вам ремонтировал машину? Так делать никогда нельзя…

— Так вы и ремонтировали…

— Ааа, ну тогда всё правильно.

Чего придираться к каким-то недочётам? Это всё варианты написания. А какие ошибки наделает писатель почитавший это объяснение, его уже дело. 

И о чём вы говорите

Stanislav Korotky #:

Пример в книге не абстрактный, а самый простой и практичный - сообщение группой расчетных алгоритмов процента выполнения конкретной задачи в планировщик задач. Это сплошь и рядом встречается.

Это где встречается «сплошь и рядом»???


зы. Вместо того чтобы критиковать, написали бы своё понятное объяснение.

 
Alexey Viktorov #:

А можете доходчиво объяснить код из учебника, после таких слов

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

Я смотрел на всё это и ничего не понимая просто закрыл не дочитав до конца…

В учебнике куча ошибок, например:

--------------

Для автоматического объекта мы получали указатель, поставив амперсанд перед его именем (в данном контексте, символ амперсанда является оператором "взятия адреса"). Так, в следующем примере переменная p указывает на автоматический объект s.

Shape s;        // автоматический объект
Shape *p = &s;  // указатель на тот же объект
------------------
Никакие адреса амперсанд в MQL4/5 не возвращает, это не С++. В MQL в угоду безопасности нет работы с адресами, как и в C# и многих других языках. Самое смешное, что строчкой выше автор правильно пишет об этой особенности.