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

 
Alexey Viktorov #:

Почему вы сделали два класса, один унаследованный от CObject и второй унаследованный от CArrayObj

Первый - элемент, второй - массив элементов.

Ведь в CArrayObj тоже есть виртуальные функции Save() и Load() и по идее они должны\могут быть переопределены в классе потомке…

CArrayObj может быть элементом (CObject*). Т.е. возможна конструкция: массив массивов.


Грубо говоря, написание virtual Save/Load в CArrayObj мог бы быть с директивой final - дальше не переопределяется.

Но на момент создания СБ язык был проще. Ну и нельзя исключать, что все же могут быть неочевидные сценарии, когда CArrayObj::Save/Load все же понадобится переопределять.

 
fxsaber #:

Первый - элемент, второй - массив элементов.

CArrayObj может быть элементом (CObject*). Т.е. возможна конструкция: массив массивов.


Грубо говоря, написание virtual Save/Load в CArrayObj мог бы быть с директивой final - дальше не переопределяется.

Но на момент создания СБ язык был проще. Ну и нельзя исключать, что все же могут быть неочевидные сценарии, когда CArrayObj::Save/Load все же понадобится переопределять.

Спасибо, ничего не понял, надо прожевать, проглотить … Может и придёт понимание. А вместе с пониманием и другие вопросы. 

Только сейчас увидел разницу… У вас список объявлен от наследника CArrayObj

      CDeals Deals;

А у меня непосредственно от CArrayObj

#include <Arrays\ArrayObj.mqh>
CArrayObj             list;

Как это влияет на выполнение кода?

 
Alexey Viktorov #:

Как это влияет на выполнение кода?

Создание CDeals-объекта позволяет в соответствующих потрохах CArrayObj вызывать переопределенные CreateElement и Type.

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Вопросы по ООП в MQL5

fxsaber, 2025.03.31 17:07

class CDeals : public CArrayObj
{
public:  
  virtual bool CreateElement( const int index ) override return(::CheckPointer(this.m_data[index] = new CDeal) == POINTER_DYNAMIC); }

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Вопросы по ООП в MQL5

fxsaber, 2025.03.31 19:20

Честно говоря, не вижу необходимости использовать эту идентификационную функцию. Но если нужно, то пропишите ее так.

class CDeals : public CArrayObj
{
public:  
   //--- method of identifying the object
  virtual int Type() const override{ ::Print(__FUNCSIG__); return(sizeof(DEAL)) ; }

// ....

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

 
fxsaber #:

Создание CDeals-объекта позволяет в соответствующих потрохах CArrayObj вызывать переопределенные CreateElement и Type.

Об этих методах узнал через ALT+G и ALT+LEFT - сильно помогают читать исходники.

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Вопросы по ООП в MQL5

fxsaber, 2025.03.31 15:37

Никогда не использовал CObject, поэтому для ответа на вопрос посмотрел исходник и сразу все понял.

Наверное, ООП-пользователи должны сразу въезжать в суть данной библиотеки по ее исходникам, потому что она использует начальный уровень ООП.

Т.е. сначала бегло прочел исходник (через горячие клавиши), понял автора библиотеки и написал соответствующий пример.


Мне не понравились примеры в Документации, Статьях и на форуме, потому что там идет захламление CObject. По этой причине ввел структуру DEAL, чтобы ООП-суть была, как на ладони.

 
fxsaber #:

Создание CDeals-объекта позволяет в соответствующих потрохах CArrayObj вызывать переопределенные CreateElement и Type.

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

Вон оно как… По абсолютному незнанию я думал, что вызывается функция последняя в иерархии наследования. Спасибо. Чуток разобрался. Теперь понимаю почему в одном случае вызывается моя виртуальная функция, а в другом из CArrayObj

fxsaber #:

Об этих методах узнал через ALT+G и ALT+LEFT - сильно помогают читать исходники.

Наверное, ООП-пользователи должны сразу въезжать в суть данной библиотеки по ее исходникам, потому что она использует начальный уровень ООП.

Т.е. сначала бегло прочел исходник (через горячие клавиши), понял автора библиотеки и написал соответствующий пример.


Мне не понравились примеры в Документации, Статьях и на форуме, потому что там идет захламление CObject. По этой причине ввел структуру DEAL, чтобы ООП-суть была, как на ладони.

Этим я пользуюсь. Но в ваших кодах всё-же сложно разбираться. 

Вот CreateElement вроде бы всё понятно, а словами объяснить последовательность не могу. Да в общем-то сейчас и не надо. Как та собака, глаза умные, всё понимаю, а сказать не могу…😊

Ну не знаю, Мне структура показалась как обезьяне стоп сигнал. Я повторить такое не смогу.

 
Alexey Viktorov #:

Ну не знаю, Мне структура показалась как обезьяне стоп сигнал. Я повторить такое не смогу.

Весь ООП в этих строках. Не больше, не меньше.

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Вопросы по ООП в MQL5

fxsaber, 2025.03.31 17:07

Ниже рабочий пример, где подсветил виртуальные функции.

#include <Arrays\ArrayObj.mqh>

class CDeal : public CObject
{
protected:
  DEAL Deal;
  
public:    
  virtual bool Save( const int file_handle ) override { return(this.Deal.Save(file_handle)); }  
  virtual bool Load( const int file_handle ) override { return(this.Deal.Load(file_handle)); }
  
  // Заполняет историей.
  CDeal* Set( const ulong lTicket ) { this.Deal.Set(lTicket); return(&this); }

};

class CDeals : public CArrayObj
{
public:  
  virtual bool CreateElement( const int index ) override return(::CheckPointer(this.m_data[index] = new CDeal) == POINTER_DYNAMIC); }
  
  // Заполняет историей.
  int Set()
  {
    const int Size = ::HistoryDealsTotal();

    for (int i = 0; i < Size; i++)
      this.Add((new CDeal).Set(::HistoryDealGetTicket(i)));
    
    return(Size);
  }
};

Т.е. код для ООП-анализа помещается на пол экрана. DEAL - любая структура. Грубо говоря, весь код выше - шаблон для работы с любыми данными. Меняется только DEAL и Set-метод.

 
fxsaber #:

Весь ООП в этих строках. Не больше, не меньше.

Т.е. код для ООП-анализа помещается на пол экрана. DEAL - любая структура. Грубо говоря, весь код выше - шаблон для работы с любыми данными. Меняется только DEAL и Set-метод.

Вот ещё какая разница в кодах… В моём коде присутствует список объектов list который можно сортировать, проверять есть-ли такой объект в списке перед добавлением и если есть, то не добавлять, получить индекс объекта в списке и его дополнять, изменять и периодически, при изменениях сохранять в файл. Потом при запуске советника прочесть всё записанное и с этим работать. Пока у меня работает так, при запуске советника идёт перебор открытых позиций, ордеров заново заполняется список объектов, по символу и с этим списком работаем. Вот хотелось бы переделать… Но не всё получается.

А в вашем коде я не понимаю где этот список…

this.m_data похож на такой список, но как его можно «употреблять» я не понимаю.

Как мне кажется, не только DEAL и Set-метод меняется.

Конечно я понимаю, что изначально не такой вопрос был и я слишком упростил его, но так уж получилось.

 
Alexey Viktorov #:

this.m_data похож на такой список, но как его можно «употреблять» я не понимаю.

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

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Вопросы по ООП в MQL5

fxsaber, 2025.03.31 17:07

  // Распечатывает себя.
  void Print() const
  {
    DEAL Array[];
    
    for (uint i = ::ArrayResize(Array, this.Total()); (bool)i--;)
      Array[i] = dynamic_cast<CDeal*>(this.At(i)).Get();
      
    ::ArrayPrint(Array);
  }

this.At[i] возвращает this.method[i], который CObject*. Далее он превращается в CDeal*, что позволяет вызвать Get-метод.

 
fxsaber #:
Через dynamic_cast возможно родительский указатель привести к указателю нужного наследника, тогда будут доступны все методы элемента массива, что прописали.

this.At[i] возвращает this.method[i], который CObject*. Далее он превращается в CDeal*, что позволяет вызвать Get-метод.

Ну всё… У меня крыша съехала, я нашёл dynamic_cast в учебнике и пойду попробую вернуть крышу взад…

Спасибо.

 
Alexey Viktorov #:

Ну всё… У меня крыша съехала, я нашёл dynamic_cast в учебнике и пойду попробую вернуть крышу взад…

Спасибо.

Простой пример

class CFoo {};

class CBar : public CFoo
  {
public:
   int get() { return MathRand() % x; }
   
private:
   const int x;
public:
   CBar(int a_x) : x(a_x) {}
  };

void OnStart()
  {
   CFoo* foo = new CBar(100);
   int result = dynamic_cast<CBar*>(foo).get();
   Print("result = ", result);
   delete foo;
  }

Я добавил x в CBar чтобы было хоть какое-то основание не делать CBar::get() статическим