Questions sur la POO dans MQL5 - page 22

 
Vladimir Simakov:

1. L'opérateur new renvoie un pointeur, bien sûr, les développeurs ont fait un gâchis avec le déréférencement implicite, donc votre version fonctionne, mais il est préférable de ne pas s'accrocher à des choses non documentées.

2. Bien sûr, ce n'est pas C++ mais c'est très similaire, donc les listes d'initialisation (je ne sais pas pour l'efficacité) sont kasher.

Vérifié, oui votre option fonctionne, et logiquement c'est plus correct :

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) Stratégie_1::Stratégie_1

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

2019.08.31 22:07:35.196 tst (EURUSD,H1) Stratégie_2::Stratégie_2

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

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) Stratégie_1::Algorithme

Le pointeur et l'objet créé à l'initialisation n'ont pas été perdus, et la méthode de l'interface n'a pas remplacé les méthodes des classes 1 et 2 - tout semble fonctionner comme prévu.

 

Comment éviter les sections de code répétitives lors de l'initialisation ? - dans le constructeur, vous ne pouvez pas

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:

Comment éviter les sections de code répétitives lors de l'initialisation ? - dans le constructeur, vous ne pouvez pas

Au lieu d'une interface, vous créez une classe ordinaire. Vous mettez *m ici et faites un bool SomeMethod {if(CheckPointer(m)) return false ; m=new... ; return true;}
Dans l'algorithme if (SomeMethod()) ...
 
Vladimir Simakov:
Au lieu d'une interface, vous créez une classe ordinaire. Là, vous mettez *m et faites de la méthode bool SomeMethod {if (CheckPointer(m)) return false ; m=new... ; return true;}
Dans l'algorithme if (SomeMethod()) ...

Non, j'ai besoin des interfaces - c'est très bien que je n'aie pas besoin de tout tirer à chaque tick - je ferai un appel d'une stratégie par tick - en général, j'aime la configuration de tout cela jusqu'ici, il semble que c'était nécessaire pour résoudre mon problème de cette façon :

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

J'ai un peu modifié mon exemple - il fonctionne, mais il devrait ressembler à ceci :

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

mais si je supprime le corps de la méthodeCStrategy::Algorithm(void), il y aura une erreur : 'Algorithm' -la fonction doit avoir un corps.

Pourquoi est-ce une erreur ? - parce que je déclare la méthode CStrategy::Algorithm(void) avec le modificateur virtual

 
Igor Makanu:

J'ai un peu modifié mon exemple - il fonctionne, mais il devrait ressembler à ceci :

mais si je supprime le corps de la méthode CStrategy::Algorithm(void), il y aura une erreur : 'Algorithm' - la fonction doit avoir un corps.

Pourquoi est-ce une erreur ? - parce que je déclare la méthode CStrategy::Algorithm(void) avec le modificateur virtual

Une méthode abstraite doit être implémentée dans les descendants. Encore une fois, il n'y a pas besoin d'interface ici.
 
virtual void Algoritm()=0 ;
Essayez ça.
 
Vladimir Simakov:
virtual void Algoritm()=0 ;
Essayez ça.
Non, ça ne marchera pas non plus. Si vous déclarez une abstraction, ayez la gentillesse de l'implémenter.
 
Vladimir Simakov:
Non, ça ne marchera pas non plus. Si vous déclarez une abstraction, ayez la gentillesse de l'implémenter.

Je pense que le compilateur perçoit la méthode Algorithm() de l'interface et la méthode déclarée virtual void Algorithm() comme des méthodes différentes en raison du modificateur virtual.

Vladimir Simakov:
Une méthode abstraite doit être implémentée dans les descendants. Encore une fois, il n'est pas nécessaire de le mettre en œuvre.

J'ai besoin d'interfaces parce qu'il est pratique pour moi de déclarer un comportement différent pour 6 stratégies en fonction des paramètres du conseiller expert (il n'y a pas tant de stratégies que de systèmes d'ordres).

en ce moment :

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

Je veux minimiser le corps des méthodes Algorithm() - si j'écris correctement la classe de base - dans mon exemple, la classe CStrategy, alors l'Algorithm() lui-même contiendra 5-10 lignes au maximum.


Comment dois-je écrire ce code sans interface ? - Maintenant tout est bref et il ne restera plus qu'à tirer les algorithmes eux-mêmes des stratégies tous les tick ou moins fréquemment.

 

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

Je vous montrerai ce soir. Je suis sur mon téléphone en ce moment.