Учёба. Классы. Нужна помощь. - страница 17

 
Sergey Gridnev #:

Перечитайте оба моих сообщения вдумчиво. Простая перегрузка методов не будет работать также. Класс CArray оперирует объектами CObject, он не знает про наследников. Если Compare не виртуальный, то будет вызван метод Compare класса CObject, а если виртуальный - класса-потомка.

Наверное вы не дочитали моё сообщение

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

Учёба. Классы. Нужна помощь.

Alexey Viktorov, 2024.12.16 10:35

То-есть функция в потомке просто заменяет функцию родителя?

Если так, то зачем всё это городить если простая функция будет работать так-же… В чём прикол? В чём полезность виртуальности?

Ну в том примере, что привёл я, это не я писал, там более-менее понятно. Внутри классов СArray и  СArrayObj неоднократно вызывается метод Compare и в этом случае понятно будет замена. А вот объяснения с классом CTrade совсем не догоняю.


 
Denis Kirichenko #:

Алексей, у Вас есть критическое мышление, что продвигает Вас на шаг ближе ))

Вот возьмём мой пример выше и просто переопределим метод озвучивания.

В журнале мы увидим такое:


Т.е. программа всегда вызывала метод родительского класса, без учёта классовой иерархии.

Это вы говорите о том, чей конструктор будет вызван. А я о другом, примитивном…

 
Alexey Viktorov #:

Это вы говорите о том, чей конструктор будет вызван. А я о другом, примитивном…

Он про метод Sound
 
Alexey Viktorov #:

Это вы говорите о том, чей конструктор будет вызван. А я о другом, примитивном…

Попробуйте в Отладчике пройтись по коду в обоих моих примерах, с заходом в тело метода Sound(). Увидите разницу ))

 
Sergey Gridnev #:
Он про метод Sound
Denis Kirichenko #:

Попробуйте в Отладчике пройтись по коду в обоих моих примерах, с заходом в тело метода Sound(). Увидите разницу ))

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

Видимо прав fxsaber

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

Учёба. Классы. Нужна помощь.

fxsaber, 2024.12.16 10:30

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

А этот пример с котом и собакой, кажется не сложно переписать на уровне примитива.
 
Alexey Viktorov #:

Видимо прав fxsaber

В этом правиле есть одно исключение.

class A
{
public:  
  virtual void m() { Print(__FUNCSIG__); }
};

class B : public A
{
public:  
  virtual void m() { Print(__FUNCSIG__); }
};

void f( A& a ) { a.m(); }

void OnStart()
{
  B b;
  
  f(b); // void B::m()
}

Указатели не задействованы, но виртуальность используется.

 
fxsaber #:

В этом правиле есть одно исключение.

Указатели не задействованы, но виртуальность используется.

А причём тут указатели или нет? Если есть полиморфная связь между классами, то она и так сработает. Лишь бы компилятор пропустил... И указатель, в любом случае, можно с любого объекта получить в виде автоматического...

Например:

class CiAnimal
   {
   public:
      virtual void Sound()
         {
         Print("silent");
         }; // звук, который издает животное
   };
//+------------------------------------------------------------------+
//|  Класс CCat наследуется от класса CiAnimal                       |
//+------------------------------------------------------------------+
class CCat : public CiAnimal
   {
   public:
      CCat()
         {
         Print("Cat was born");
         }
      ~CCat()
         {
         Print("Cat is dead");
         }
      void Sound() override
         {
         Print("meou");
         }
   };
//+------------------------------------------------------------------+
//|  Класс CDog наследуется от класса CiAnimal                       |
//+------------------------------------------------------------------+
class CDog : public CiAnimal
   {
   public:
      CDog()
         {
         Print("Dog was born");
         }
      ~CDog()
         {
         Print("Dog is dead");
         }
      void Sound() override
         {
         Print("guaf");
         }
   };
//+------------------------------------------------------------------+
//|  Класс CTurtle наследуется от класса CiAnimal                    |
//+------------------------------------------------------------------+
class CTurtle : public CiAnimal
   {
   public:
      CTurtle()
         {
         Print("Turtle was born");
         }
      ~CTurtle()
         {
         Print("Turtle is dead");
         }
   };
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
   {
   //--- массив указателей на объекты типа CiAnimal
   CiAnimal *animals[3];
   //--- породим потомков CiAnimal и сохраним указатели на них в массив
   /*animals[0] = new CCat;
   animals[1] = new CDog;
   animals[2] = new CTurtle;*/
   CCat cat;
   animals[0] = &cat;
   CDog dog;
   animals[1] = &dog;
   CTurtle turtle;
   animals[2] = &turtle;
   //--- вызовем метод Sound() для каждого потомка
   for(int i = 0; i < ArraySize(animals); ++i)
      animals[i].Sound();
   //--- удалять ничего не нужно
   /*for(int i = 0; i < ArraySize(animals); ++i)
      delete animals[i];*/
   }
//+------------------------------------------------------------------+
 
Alexey Viktorov #:
А этот пример с котом и собакой, кажется не сложно переписать на уровне примитива.

Перепишите.

Задача: указанное в настройках количество собак и котов должны издать свой звук. Все животные должны быть собраны в один общий массив (для чего может понадобиться собирать объекты в один массив - подумайте сами).

#property script_show_inputs

input int numberOfDogs = 7;
input int numberOfCats = 8;

class CAnimal
  {
public:
   static void  addToArray(CAnimal*&arr[], CAnimal* instance);
protected:
   const string name;
public:
   virtual void speak() = 0;
                CAnimal(string a_name) : name(a_name) {}
  };

void CAnimal::addToArray(CAnimal *&arr[], CAnimal* instance)
  {
   int idx = ArraySize(arr);
   ArrayResize(arr, idx + 1, 100);
   arr[idx] = instance;
  }

class CCat : public CAnimal
  {
public:
   void speak() override { Print(name, " meow"); }
        CCat(string a_name) : CAnimal(a_name) {}
  };

class CDog : public CAnimal
  {
public:
   void speak() override { Print(name, " woof"); }
        CDog(string a_name) : CAnimal(a_name) {}
  };


void OnStart()
  {
   CAnimal* animals[];
   // Добавляем всех в один массив
   for(int i = 1; i <= numberOfDogs; i++)
      CAnimal::addToArray(animals, new CDog("Dog#" + (string)i));
   for(int i = 1; i <= numberOfCats; i++)
      CAnimal::addToArray(animals, new CCat("Cat#" + (string)i));
   // Заставляем всех издавать звуки
   for(int i = ArraySize(animals) - 1; i >= 0; i--)
      animals[i].speak();
   //---
   for(int i = ArraySize(animals) - 1; i >= 0; i--)
      delete animals[i];
  }

[edit]

исправил опечатку в коде (ранее количество котов зависило от numberOfDogs, а не от numberOfCats)

 
Vladislav Boyko #:
Все животные должны быть собраны в один общий массив (для чего может понадобиться собирать объекты в один массив - подумайте сами).

Представьте, что это какие-нибудь фильтры сигнала. Все фильтры сигнала выполняют одно и то-же действие - проверяют, разрешено ли покупать/продавать с помощью методов checkBuy() и checkSell(). Но каждый фильтр делает собственные проверки (один проверяет MA, второй проверяет RSI). Каждый фильтр может быть включен или отключен в настройках. Вы не знаете, сколько именно фильтров активировал в настройках пользователь. Вам нужно проверить все активные фильтры в нескольких местах программы. Вы будете каждый раз городить портяну из if, в которых будете проверять включен ли каждый фильтр в настройках? Или может лучше будет в OnInit() создать массив, куда собрать только те фильтры, которые включены в настройках?

 
Vladislav Boyko #:

Перепишите.

Задача: указанное в настройках количество собак и котов должны издать свой звук. Все животные должны быть собраны в один общий массив (для чего может понадобиться собирать объекты в один массив - подумайте сами).

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

Правки в ООП код заняли минут 15, сколько времени займут правки процедурного кода?

P.S. И еще одно. Мне частно нужны животные в разных программах. Я хочу положить весь связанный с животными код в отдельный файл .mqh файл. А input настройки должны остаться в .mq5 файле.

P.S.2 В будущем может понадобиться сделать так, что бы звуки издавали только животные с четным или с нечетным номером. Не индексом в массиве, а тем номером, который содержится в имени животного. Как быстро можно добавить такой функционал для процедурного кода?

#property script_show_inputs

input int numberOfDogs = 3;
input int numberOfCats = 3;

class CAnimal
  {
public:
   static void  addToArray(CAnimal*&arr[], CAnimal* instance);
protected:
   const string name;
public:
   virtual void speak() = 0;
                CAnimal(string a_name) : name(a_name) {}
  };

void CAnimal::addToArray(CAnimal *&arr[], CAnimal* instance)
  {
   int idx = ArraySize(arr);
   ArrayResize(arr, idx + 1, 100);
   arr[idx] = instance;
  }

class AnimalRepository
  {
private:
   CAnimal* animals[];
public:
   void     add(CAnimal* instance) { CAnimal::addToArray(animals, instance); }
   void     callSpeakForAll();
   void     shuffle();
            ~AnimalRepository();
  };

AnimalRepository::~AnimalRepository(void)
  {
   for(int i = ArraySize(animals) - 1; i >= 0; i--)
      delete animals[i];
  }

void AnimalRepository::callSpeakForAll(void)
  {
   for(int i = ArraySize(animals) - 1; i >= 0; i--)
      animals[i].speak();
  }

void AnimalRepository::shuffle(void)
  {
   for(int i = ArraySize(animals) - 1; i > 0; i--)
     {
      int j = MathRand() % (i + 1);
      CAnimal* temp = animals[i];
      animals[i] = animals[j];
      animals[j] = temp;
     }
  }

class CCat : public CAnimal
  {
public:
   void speak() override { Print(name, " meow"); }
        CCat(string a_name) : CAnimal(a_name) {}
  };

class CDog : public CAnimal
  {
public:
   void speak() override { Print(name, " woof"); }
        CDog(string a_name) : CAnimal(a_name) {}
  };


void OnStart()
  {
   AnimalRepository repo;
   //--- Создаем животных
   for(int i = 1; i <= numberOfDogs; i++)
      repo.add(new CDog("Dog#" + (string)i));
   for(int i = 1; i <= numberOfCats; i++)
      repo.add(new CCat("Cat#" + (string)i));
   //--- Все издают звуки
   Print("До перемешивания:");
   repo.callSpeakForAll();
   //--- Перемешиваем
   repo.shuffle();
   //--- Снова издаем звуки
   Print("После перемешивания:");
   repo.callSpeakForAll();
  }