Domande su OOP in MQL5 - pagina 22

 
Vladimir Simakov:

1. il nuovo operatore restituisce un puntatore, naturalmente, gli sviluppatori hanno fatto un casino con la dereferenziazione implicita, quindi la tua versione funziona, ma è meglio non rimanere bloccati su cose non documentate.

2. Certo, non abbiamo C++, ma è molto simile, quindi le liste di inizializzazione (non so per l'efficienza) sono kosher.

Controllato, sì, la tua opzione funziona, e logicamente è più corretta:

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

2019.08.31 22:07:35.196 tst (EURUSD,H1) Strategy_2::Strategy_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) Strategy_2::Algorithm

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

Il puntatore e l'oggetto creato all'inizializzazione non sono stati persi, e il metodo nell'interfaccia non ha sostituito i metodi delle classi 1 e 2 - tutto sembra funzionare come previsto

 

Come posso evitare sezioni di codice ripetitive durante l'inizializzazione? - nel costruttore non si può

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:

Come posso evitare sezioni di codice ripetitive durante l'inizializzazione? - nel costruttore, non è possibile

Al posto dell'interfaccia fate una classe normale. Ci metti *m e fai un bool SomeMethod {if(CheckPointer(m)) return false; m=new...; return true;}
In Algoritmo if (SomeMethod()) ...
 
Vladimir Simakov:
Invece dell'interfaccia, fate una classe normale. Lì metti *m e rendi il metodo bool SomeMethod {if (CheckPointer(m)) return false; m=new...; return true;}
In Algoritmo if (SomeMethod()) ...

No, ho bisogno delle interfacce - è molto bello che non avrò bisogno di tirare tutto ad ogni tick - farò una chiamata di una strategia per un tick - in generale mi piace la configurazione di tutto questo finora, sembra che sia stato necessario per risolvere il mio problema in questo modo:

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

Ho modificato un po' il mio esempio - funziona, ma dovrebbe apparire così:

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

ma se rimuovo il corpo del metodoCStrategy::Algorithm(void), ci sarà un errore: 'Algorithm' -la funzione deve avere un corpo

Perché è un errore? - perché dichiaro il metodo CStrategy::Algorithm(void) con il modificatore virtual

 
Igor Makanu:

Ho modificato un po' il mio esempio - funziona, ma dovrebbe apparire così:

ma se rimuovo il corpo del metodo CStrategy::Algorithm(void), ci sarà un errore: 'Algorithm' - la funzione deve avere un corpo

Perché è un errore? - perché dichiaro il metodo CStrategy::Algorithm(void) con il modificatore virtual

Un metodo astratto deve essere implementato nei discendenti. Ancora una volta, non c'è bisogno di un'interfaccia qui.
 
virtual void Algoritm()=0;
Prova questo.
 
Vladimir Simakov:
virtual void Algoritm()=0;
Prova questo.
No, neanche questo funzionerà. Se dichiarate un'astrazione, siate abbastanza gentili da implementarla.
 
Vladimir Simakov:
No, neanche questo funzionerà. Se dichiarate un'astrazione, siate abbastanza gentili da implementarla.

Penso che il compilatore percepisca il metodo Algoritmo() dall'interfaccia e il vuoto virtuale dichiarato Algoritmo() come metodi diversi a causa del modificatore virtuale

Vladimir Simakov:
Un metodo astratto deve essere implementato nei discendenti. Ancora una volta, non c'è bisogno di implementarlo.

Ho bisogno di interfacce perché è conveniente per me dichiarare un comportamento diverso per 6 strategie a seconda delle impostazioni di Expert Advisor (non ci sono molte strategie ma sistemi di ordini)

in questo momento:

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

Voglio minimizzare il corpo dei metodi Algorithm() - se scrivo correttamente la classe base - nel mio esempio, la classe CStrategy, allora la stessa Algorithm() conterrà 5-10 linee al massimo


Come dovrei scrivere questo codice senza un'interfaccia? - Ora tutto è breve e non rimarrà che tirare gli algoritmi stessi strategie ogni tick o meno frequentemente

 

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

Te lo mostrerò stasera. Sono al telefono in questo momento.