Perguntas sobre OOP em MQL5 - página 22

 
Vladimir Simakov:

1. O novo operador devolve um ponteiro, é claro, os desenvolvedores fizeram uma bagunça com o desreferenciamento implícito, então sua versão funciona, mas é melhor não ficar pendurado em coisas não documentadas.

2. É claro que não é C++, mas é muito semelhante, portanto as listas de inicialização (não sei sobre eficiência) são kosher.

Checado, sim sua opção funciona, e logicamente é mais correta:

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) Strategy_1::Strategy_1

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

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

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

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

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

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

O ponteiro e o objeto criado na inicialização não foram perdidos, e o método na interface não substituiu os métodos das classes 1 e 2 - tudo parece funcionar como planejado

 

Como posso evitar seções de código repetitivas durante a inicialização? - no construtor você não pode

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:

Como posso evitar seções de código repetitivas durante a inicialização? - no construtor, você não pode

Em vez de interface, você faz uma classe comum. Você coloca *m lá e faz um bool SomeMethod {if(CheckPointer(m)) return false; m=new...; return true;}
Em Algoritm if (SomeMethod()) ...
 
Vladimir Simakov:
Em vez de interface, você faz uma classe regular. Aí você coloca *m e faz o método bool SomeMethod {if (CheckPointer(m)) return false; m=new...; return true;}
Em Algoritm if (SomeMethod()) ...

Não, eu preciso dos interfes - é muito legal que eu não precise puxar tudo a cada tique - eu farei uma chamada de uma estratégia por tique - em geral eu gosto da configuração de tudo isso até agora, parece que foi necessário resolver meu problema desta maneira:

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();
  }
//+------------------------------------------------------------------+
 

Afinei um pouco o meu exemplo - funciona, mas deveria ser assim:

//+------------------------------------------------------------------+
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

mas se eu remover o corpo daestratégia CSt::Algoritmo(nulo) método, haverá um erro: 'Algoritmo' -a função deve ter um corpo

Por que é um erro? - porque declaro a estratégia CSt::Método Algoritmo(nulo) com o modificador virtual

 
Igor Makanu:

Afinei um pouco o meu exemplo - funciona, mas deveria ser assim:

mas se eu remover o corpo da estratégia CSt::Algoritmo(nulo) método, haverá um erro: 'Algoritmo' - a função deve ter um corpo

Por que é um erro? - porque declaro a estratégia CSt::Método Algoritmo(nulo) com o modificador virtual

Um método abstrato deve ser implementado nos descendentes. Mais uma vez, não há necessidade de interface aqui.
 
vazio virtual Algoritm()=0;
Tente isto.
 
Vladimir Simakov:
vazio virtual Algoritm()=0;
Tente isto.
Não, isso também não vai funcionar. Se você declarar uma abstração, seja gentil o suficiente para implementá-la.
 
Vladimir Simakov:
Não, isso também não vai funcionar. Se você declarar uma abstração, seja gentil o suficiente para implementá-la.

Acho que o compilador percebe o método Algorithm() da interface e o Algorithm() declarado vazio virtual como métodos diferentes por causa do modificador virtual

Vladimir Simakov:
Um método abstrato deve ser implementado nos descendentes. Mais uma vez, não há necessidade de implementá-lo.

Preciso de interfaces porque é conveniente para mim declarar comportamentos diferentes para 6 estratégias, dependendo das configurações do Expert Advisor (não há tantas estratégias, mas pesquisa de sistemas de pedidos)

agora mesmo:

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; } } }

Eu quero minimizar o corpo dos métodos Algorithm() - se eu escrever a classe base corretamente - no meu exemplo, a classe CStrategy, então o Algorithm() em si conterá no máximo 5-10 linhas


Como devo escrever este código sem uma interface? - Agora tudo é breve e só restará puxar as estratégias dos próprios algoritmos a cada tique ou com menos freqüência.

 

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

Mostrarei a vocês esta noite. Estou no meu telefone agora mesmo.
Razão: