Preguntas sobre POO en MQL5 - página 22

 
Vladimir Simakov:

1. el operador new devuelve un puntero, por supuesto, los desarrolladores se hicieron un lío con la desreferenciación implícita, por lo que tu versión funciona, pero es mejor no quedarse con cosas indocumentadas.

2. Por supuesto, no tenemos C++, pero es muy parecido, así que las listas de inicialización (no sé si de eficiencia) son kosher.

Comprobado, sí que funciona tu opción, y lógicamente es más correcta:

interface IStrategy
  {
   void Algorithm()  { Print("Это не должно вызываться!!!"); }
  };
//+------------------------------------------------------------------+
class Strategy_1 : public IStrategy
  {
public:
                     Strategy_1()   { Print(__FUNCTION__); }
   void              Algorithm()    { Print(__FUNCTION__); }
  };
//+------------------------------------------------------------------+
class Strategy_2 : public IStrategy
  {
public:
                     Strategy_2()   { Print(__FUNCTION__); }
   void              Algorithm()    { Print(__FUNCTION__); }
  };
//+------------------------------------------------------------------+
class Context
  {
public:
   IStrategy         *s;
                     Context(IStrategy *_strategy) { Print(__FUNCTION__); s = _strategy;              }
                    ~Context()                     { delete s;                                        }
   void              GetStrategy()                 { s.Algorithm();                                   }
  };
//+------------------------------------------------------------------+
Context c1(new Strategy_1);
Context c2(new Strategy_2);
//+------------------------------------------------------------------+
void OnStart()
  {
   c1.GetStrategy();
   c2.GetStrategy();
   
   c1.s.Algorithm();
  }
//+------------------------------------------------------------------+

2019.08.31 22:07:35.196 tst (EURUSD,H1) Estrategia_1::Estrategia_1

2019.08.31 22:07:35.196 tst (EURUSD,H1) Context::Context

2019.08.31 22:07:35.196 tst (EURUSD,H1) Estrategia_2::Estrategia_2

2019.08.31 22:07:35.196 tst (EURUSD,H1) Context::Context

2019.08.31 22:07:35.196 tst (EURUSD,H1) Strategy_1::Algorithm

2019.08.31 22:07:35.196 tst (EURUSD,H1) Estrategia_2::Algoritmo

2019.08.31 22:07:35.197 tst (EURUSD,H1) Strategy_1::Algorithm

El puntero y el objeto creado en la inicialización no se han perdido, y el método de la interfaz no ha sustituido a los métodos de las clases 1 y 2 - todo parece funcionar como estaba previsto

 

¿Cómo puedo evitar las secciones de código repetitivas durante la inicialización? - en el constructor no se puede

class MyClass
{
   public:
      MyClass()         {Print("Create MyClass");}
};

interface IStrategy
  {
   void Algorithm()  { Print("Это не должно вызываться!!!"); }
  };
//+------------------------------------------------------------------+
class Strategy_1 : public IStrategy
  {
  private:
  MyClass   *m;
public:
                     Strategy_1()   { Print(__FUNCTION__); }
   void              Algorithm()    { if(m==NULL) m = new MyClass; else { } } 
  };
//+------------------------------------------------------------------+
class Strategy_2 : public IStrategy
  {
  private:
  MyClass   *m;
public:
                     Strategy_2()   { Print(__FUNCTION__); }
   void              Algorithm()    { if(m==NULL) m = new MyClass; else { } }
  };
//+------------------------------------------------------------------+
class Context
  {
private:
   IStrategy         *s;
public:
                     Context(IStrategy *_strategy) { Print(__FUNCTION__); s = _strategy;              }
                    ~Context()                     { delete s;                                        }
   void              GetStrategy()                 { s.Algorithm();                                   }
  };
//+------------------------------------------------------------------+
Context c1(new Strategy_1);
Context c2(new Strategy_2);
//+------------------------------------------------------------------+
void OnStart()
  {
   c1.GetStrategy();
   c2.GetStrategy();
  }
//+------------------------------------------------------------------+
 
Igor Makanu:

¿Cómo puedo evitar las secciones de código repetitivas durante la inicialización? - en el constructor, no se puede

En lugar de la interfaz se hace una clase ordinaria. Pones *m ahí y haces un bool SomeMethod {if(CheckPointer(m)) return false; m=new...; return true;}
En el algoritmo if (SomeMethod()) ...
 
Vladimir Simakov:
En lugar de la interfaz, se hace una clase normal. Ahí pones *m y haces el método bool SomeMethod {if (CheckPointer(m)) return false; m=new...; return true;}
En el algoritmo if (SomeMethod()) ...

No, necesito las interfases - es muy bueno que no necesitaré tirar de todo en cada tick - haré una llamada de una estrategia por un tick - en general me gusta la configuración de todo esto hasta ahora, parece que era necesario para resolver mi problema de esta manera:

class MyClass
{
   public:
      MyClass()         {Print("Create MyClass");}
};

interface IStrategy
  {
   void Algorithm()  { Print("Это не должно вызываться!!!"); }
  };
  
class CStrategy : public IStrategy
{
protected:
   MyClass  *m;
   void Init()   {  m=new MyClass; }
};
//+------------------------------------------------------------------+
class Strategy_1 : public CStrategy
  {
public:
                     Strategy_1()   { Print(__FUNCTION__); }
   void              Algorithm()    { if(m==NULL) Init(); else { } } 
  };
//+------------------------------------------------------------------+
class Strategy_2 : public CStrategy
  {
public:
                     Strategy_2()   { Print(__FUNCTION__); }
   void              Algorithm()    { if(m==NULL) Init(); else { } }
  };
//+------------------------------------------------------------------+
class Context
  {
private:
   IStrategy         *s;
public:
                     Context(IStrategy *_strategy) { Print(__FUNCTION__); s = _strategy;              }
                    ~Context()                     { delete s;                                        }
   void              GetStrategy()                 { s.Algorithm();                                   }
  };
//+------------------------------------------------------------------+
Context c1(new Strategy_1);
Context c2(new Strategy_2);
//+------------------------------------------------------------------+
void OnStart()
  {
   c1.GetStrategy();
   c2.GetStrategy();
  }
//+------------------------------------------------------------------+
 

He retocado un poco mi ejemplo - funciona, pero debería tener este aspecto:

//+------------------------------------------------------------------+
interface IStrategy
{  void Algorithm()                 {Print("Это не должно запускаться!!!"); } };
//+------------------------------------------------------------------+
class CStrategy : public IStrategy
{
protected:
   int x;
public:
   virtual void Algorithm()         {Print("Это не должно запускаться!!!"); } };
//+------------------------------------------------------------------+
class CStrategy_01:public CStrategy
{
public:
   CStrategy_01()                   {Print(__FUNCTION__);  x = 01;         }
   void Algorithm()                 {Print(__FUNCTION__,", x = ",x);       } };
//+------------------------------------------------------------------+
class CStrategy_02:public CStrategy
{
public:
   CStrategy_02()                   {Print(__FUNCTION__);   x = 02;        }
   void Algorithm()                 {Print(__FUNCTION__,", x = ",x);       } };
//+------------------------------------------------------------------+
class Context
{
private:
   IStrategy         *s;
public:
   Context(IStrategy *_strategy)    { Print(__FUNCTION__); s = _strategy;  }
   ~Context()                       { delete s;                            }
   void              GetStrategy()  { s.Algorithm();                       } };
//+------------------------------------------------------------------+
Context c1(new CStrategy_01);
Context c2(new CStrategy_02);
//+------------------------------------------------------------------+
void OnStart()
{  c1.GetStrategy();
   c2.GetStrategy(); }
//+------------------------------------------------------------------+



0 15:57:17.100 tst EURUSD,H1: CStrategy_01::CStrategy_01 0 15:57:17.100 tst EURUSD,H1: Context::Context 0 15:57:17.100 tst EURUSD,H1: CStrategy_02::CStrategy_02 0 15:57:17.100 tst EURUSD,H1: Context::Context 0 15:57:17.100 tst EURUSD,H1: initialized 0 15:57:17.100 tst EURUSD,H1: CStrategy_01::Algorithm, x = 1 0 15:57:17.100 tst EURUSD,H1: CStrategy_02::Algorithm, x = 2

pero si elimino el cuerpo del métodoCStrategy::Algorithm(void), habrá un error: 'Algorithm' -la función debe tener un cuerpo

¿Por qué es un error? - porque declaro el método CStrategy::Algorithm(void) con el modificador virtual

 
Igor Makanu:

He ajustado un poco mi ejemplo - funciona, pero debería tener este aspecto:

pero si elimino el cuerpo del método CStrategy::Algorithm(void), habrá un error: 'Algorithm' - la función debe tener un cuerpo

¿Por qué es un error? - porque declaro el método CStrategy::Algorithm(void) con el modificador virtual

Un método abstracto debe ser implementado en los descendientes. Una vez más, no hay necesidad de interfaz aquí.
 
virtual void Algoritm()=0;
Prueba esto.
 
Vladimir Simakov:
virtual void Algoritm()=0;
Prueba esto.
No, eso tampoco funcionará. Si declara una abstracción, tenga la amabilidad de implementarla.
 
Vladimir Simakov:
No, eso tampoco funcionará. Si declaras una abstracción, ten la amabilidad de implementarla.

Creo que el compilador percibe el método Algorithm() de la interfaz y el void virtual declarado Algorithm() como métodos diferentes debido al modificador virtual

Vladimir Simakov:
Un método abstracto debe ser implementado en los descendientes. Una vez más, no es necesario aplicarlo.

Necesito interfaces porque me conviene declarar un comportamiento diferente para 6 estrategias dependiendo de la configuración del Asesor Experto (no hay tantas estrategias sino sistemas de órdenes)

ahora mismo:

class CGrid {
private:
   int               StrategyCount;
   IStrategy         *Strategy[];
public:
   CGrid(int eamagicnumber, SSettingsForOrder &settingstrategy[]);
   ~CGrid(); };
//+------------------------------------------------------------------+
void CGrid::CGrid(int eamagicnumber, SSettingsForOrder &settingstrategy[]) {
   StrategyCount = ArraySize(settingstrategy);
   ArrayResize(Strategy, StrategyCount);
   for(int i = 0; i < StrategyCount; i++) {
      settingstrategy[i].magicnumber = i+eamagicnumber;
      switch(settingstrategy[i].dealtype) {
      case NONE                  :  Strategy[i] = new CNONE(settingstrategy[i]);                   break;
      case BUY                   :  Strategy[i] = new CBUY(settingstrategy[i]);                    break;
      case ReOpenBUY             :  Strategy[i] = new CReOpenBUY(settingstrategy[i]);              break;
      case ReversBUYToSellOnly   :  Strategy[i] = new CReversBUYToSellOnly(settingstrategy[i]);    break;
      case ReversBUYAlwaysRevers :  Strategy[i] = new CReversBUYAlwaysRevers(settingstrategy[i]);  break;
      case SELL                  :  Strategy[i] = new CSELL(settingstrategy[i]);                   break;
      case ReOpenSELL            :  Strategy[i] = new CReOpenSELL(settingstrategy[i]);             break;
      case ReversSELLToBuyOnly   :  Strategy[i] = new CReversSELLToBuyOnly(settingstrategy[i]);    break;
      case ReversSELLAlwaysRevers:  Strategy[i] = new CReversSELLAlwaysRevers(settingstrategy[i]); break; } } }

Quiero minimizar el cuerpo de los métodos de Algorithm() - si escribo la clase base correctamente - en mi ejemplo, la clase CStrategy, entonces el propio Algorithm() contendrá 5-10 líneas como máximo


¿Cómo debo escribir este código sin una interfaz? - Ahora todo es breve y sólo quedará tirar de los propios algoritmos como estrategias cada tick o con menos frecuencia

 

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

Te lo enseñaré esta noche. Estoy en mi teléfono ahora mismo.