Questions sur la POO dans MQL5 - page 20

 
Koldun Zloy:
Variable statique, elle sera la même pour toutes les instances sans héritage.

J'ai vérifié, et bien oui ! il s'est avéré que c'était plus simple que ça !

/+------------------------------------------------------------------+
string MyTerminalInfoString()
  {
   Print(__FUNCTION__);
   return("ru");
  }
//+------------------------------------------------------------------+
class B
  {
  protected:
   static const string Language;
public:
                     B() {Print(__FUNCTION__,Language); }
  };
//+------------------------------------------------------------------+
static const string B::Language=MyTerminalInfoString();
//+------------------------------------------------------------------+
B *arrB[5];
//+------------------------------------------------------------------+
int OnInit()
  {
   for(int i=0; i<5; i++)
      arrB[i] = new B;
   return(INIT_SUCCEEDED);
  }

2019.08.29 15:14:09.847 tst__ EURUSD,M15 : initialisé

2019.08.29 15:14:09.847 tst__ EURUSD,M15 : B::Bru

2019.08.29 15:14:09.847 tst__ EURUSD,M15 : B::Bru

2019.08.29 15:14:09.847 tst__ EURUSD,M15 : B::Bru

2019.08.29 15:14:09.847 tst__ EURUSD,M15 : B::Bru

2019.08.29 15:14:09.847 tst__ EURUSD,M15 : B::Bru

2019.08.29 15:14:09.847 tst__ EURUSD,M15 : MyTerminalInfoString

Je vois que la variable Language n'a été initialisée qu'une seule fois, c'est-à-dire qu'il s'agit d'une solution plus simple

Merci !

 
Roman:

Dites-moi, en quoi est-ce différent ?
Créer un objet, ou un pointeur, de cette manière

de la création classique

La différence est que dans le premier cas, il n'est pas nécessaire de spécifier l'identifiant de classeCClass en C++.

 

J'ai esquissé ma classe, qui doit initialiser les champs une fois avec des valeurs constantes, et cela semble fonctionner comme prévu :

class Cdeal : public CObject
  {

private:
   static const double VolumeMAX;
   static const double VolumeMIN;
   static const double VolumeSTEP;
   static const int  VolumeDIGITS;
   static int        GetDigitsInVolumeStep();
   SSettingsForOrder m_set;
public:
                     Cdeal(SSettingsForOrder &set);
  };
//____________________________________________________________________
static int Cdeal::GetDigitsInVolumeStep()
  {
   long i=10000000,k=long(::SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP)/0.0000001);
   int result=0;
   while(result<7 && k%i>0)
     {
      i/=10;
      result++;
     }
   return(result);
  }
//____________________________________________________________________
static const double Cdeal::VolumeMAX = ::SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
//____________________________________________________________________
static const double Cdeal::VolumeMIN = ::SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
//____________________________________________________________________
static const double Cdeal::VolumeSTEP = ::SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
//____________________________________________________________________
static const int Cdeal::VolumeDIGITS = Cdeal::GetDigitsInVolumeStep();
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
Cdeal::Cdeal(SSettingsForOrder &set)
  {
   m_set = set;
  }
//+------------------------------------------------------------------+

Je n'aime pas 2 choses :

1. je répète l'appel de SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP) - parce que l'ordre d'initialisation n'est pas défini, c'est-à-dire qu'il n'est pas sûr que VolumeSTEP sera initialisé en premier et seulement ensuiteGetDigitsInVolumeStep() sera appelé

2. je veux me débarrasser de la méthode statique static int GetDigitsInVolumeStep() - j'ai vu une vidéo sur youtube disant qu'en pure POO on ne devrait pas utiliser de méthodes statiques, et maintenant je me bats contre des moulins à vent

le lien vers la vidéo, c'est essentiellement la même chosehttps://youtu.be/lfdAwl3-X_c ethttps://youtu.be/zME4SOCHT0I


comment puis-je réécrire différemment ces 2 points que je n'aime pas ?

 
Igor Makanu:

1. je répète l'appel à SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP) - parce que l'ordre d'initialisation n'est pas spécifié, c'est-à-dire qu'il n'est pas certain que j'aurai VolumeSTEP initialisé en premier, et qu'ensuite seulement GetDigitsInVolumeStep() sera appelé

1. c'est-à-dire que vous craignez que l'ordre d'initialisation de la statique soit indéfini ? En fait, ce n'est pas le cas, les plus s'initialisent dans l'ordre de leur définition dans le code. Alors, ne vous inquiétez pas, faites d'abord le VolumeSTEP, puis le VolumeDIGITS.

 
Vict:

1) Vous craignez donc que l'ordre d'initialisation de la statique ne soit pas défini ? En fait, ce n'est pas le cas, dans les plus, l'initialisation est dans l'ordre de la définition dans le code. Alors ne vous inquiétez pas, d'abord VolumeSTEP et ensuite VolumeDIGITS.

Oui, non pas que j'aie peur, disons que je suis protégé, je crois que le code devrait avoir au moins une certaine garantie contre les changements de comportement de la compilation - en général OUI.

ZS : ici en général, pourquoi le sujet pour la première fois un jour - je veux voir comment réaliste de faire quelque chose comme dans la vidéo auteur Egor dit, alors que je doute que nous obtenons quelque chose d'efficace - maintenant, je suis en utilisant des méthodes statiques, et avec l'initialisation sont déjà quelques doutes apparus

 
Vict:

1. c'est-à-dire que vous craignez que l'ordre d'initialisation de la statique soit indéfini ? En fait, ce n'est pas le cas, les plus s'initialisent dans l'ordre de leur définition dans le code. Alors, ne vous inquiétez pas, faites d'abord le VolumeSTEP, puis le VolumeDIGITS.

Dans MQL aussi.

https://www.mql5.com/ru/docs/basis/oop/staticmembers

Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Статические члены класса
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Статические члены класса
  • www.mql5.com
Члены класса могут быть объявлены с использованием модификатора класса памяти static. Такие члены данных разделяются всеми экземплярами данного класса и хранятся в одном месте. Нестатические члены данных создаются для каждой переменной-объекта класса. Отсутствие возможности объявлять статически члены класса привело бы к необходимости объявлять...
 
Igor Makanu:

Oui, non pas que j'aie peur, disons que je suis protégé, je crois que le code devrait avoir au moins une certaine garantie contre les changements de comportement de la compilation - en général OUI.

ZS : ici en général, pourquoi le sujet pour la première fois un jour - Je veux voir comment réaliste de faire quelque chose comme dans la vidéo auteur Egor dit, alors que je doute que nous allons obtenir quelque chose d'efficace - maintenant, je suis en utilisant des méthodes statiques, et avec l'initialisation sont déjà quelques doutes apparus

#ifndef _C_TRADE_CONST_
#define _C_TRADE_CONST_

#define TRADE_CONST_DECL  CTradeConst* cTradeConst
#define TRADE_CONST  cTradeConst
#define _symbol      cTradeConst.symbol
#define _lotDigits   cTradeConst.lotDigits
#define _lotStep     cTradeConst.lotStep
#define _lotMax      cTradeConst.lotMax
#define _lotMin      cTradeConst.lotMin
#define _tickSize    cTradeConst.tickSize
#define _point       cTradeConst.point
#define _stopLevel   cTradeConst.stopLevel
#define _freezeLevel cTradeConst.freezeLevel
#define _digits      cTradeConst.digits
#ifdef __MQL5__
   #define _marginMode        cTradeConst.marginMode
   #define _executionMode     cTradeConst.executionMode
   #define _expirationMode    cTradeConst.expirationMode
   #define _fillingMode       cTradeConst.fillingMode
   #define _orderMode         cTradeConst.orderMode
#endif 

class CTradeConst
  {
public:
   string                  symbol;
   int                     lotDigits;
   double                  lotStep;
   double                  lotMax;
   double                  lotMin;
   double                  tickSize;
   double                  point;
   double                  stopLevel;
   double                  freezeLevel;
   int                     digits;
#ifdef __MQL5__
   ENUM_ACCOUNT_MARGIN_MODE      marginMode;
   ENUM_SYMBOL_TRADE_EXECUTION   executionMode;
   int                           expirationMode;
   int                           fillingMode;
   int                           orderMode;
#endif   
public:
                     CTradeConst(string mSymbol):symbol(mSymbol==NULL?_Symbol:mSymbol){if (!Init()) delete GetPointer(this);}
private:
   bool              Init();
  };
bool CTradeConst::Init(void){
   if (!MQLInfoInteger(MQL_TESTER)&&!SymbolSelect(symbol,true)) return false;
   lotStep=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP);
   lotDigits=MathMax(-(int)MathFloor(MathLog10(lotStep)),0);
   lotMax=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX);
   lotMin=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);
   point=SymbolInfoDouble(symbol,SYMBOL_POINT);
   tickSize=SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE);
   stopLevel=SymbolInfoInteger(symbol,SYMBOL_TRADE_STOPS_LEVEL)*point;
   freezeLevel=SymbolInfoInteger(symbol,SYMBOL_TRADE_FREEZE_LEVEL)*point;
   digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
#ifdef __MQL5__
   marginMode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
   executionMode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(symbol,SYMBOL_TRADE_EXEMODE);
   fillingMode=(int)SymbolInfoInteger(symbol,SYMBOL_FILLING_MODE);
   expirationMode=(int)SymbolInfoInteger(symbol,SYMBOL_EXPIRATION_MODE);
   orderMode=(int)SymbolInfoInteger(symbol,SYMBOL_ORDER_MODE);
#endif 
   return true;}
   
#endif 

Pour l'utiliser de cette façon :

#include "CTradeConst.mqh"

#define  FLAG_CONST_CREATE_HERE   0x1

class CExample{
   TRADE_CONST_DECL;
   int cFlag;
                  CExample(string mSymbol,CTradeConst* mTradeConst):
                     TRADE_CONST(!CheckPointer(mTradeConst)?new CTradeCons(mSymbol)t:mTradeConst)
                     {if (!CheckPointer(mTradeConst)) cFlag|=FLAG_CONST_CREATE_HERE;}
                 ~CExample()  {if (bool(cFlag&FLAG_CONST_CREATE_HERE)) delete TRADE_CONST;}
};

Et dans un code comme celui-ci :

CTradeConst* tradeConst=new CTradeConst;
CExampe* exsample[10];
for (int i=0;i<10;example[i++]=new CExample(_Symbol,tradeConst));
 
L'option du champ statique présente un énorme inconvénient. Vous ne pouvez pas avoir des valeurs différentes de ce champ dans différentes instances de la classe.
 
Vladimir Simakov:

Utilisez comme suit :

Et dans le code comme ceci :

oops, une petite erreur d'aiguillage, c'est ce que je peux faire.

Voici ce que je veux réaliser en général :

1. la classe CDeal est autonome, elle ouvre/ferme/contrôle son ordre par une stratégie - les stratégies sont énumérées, de sorte que l'optimiseur peut faire défiler le mélange de stratégies.

2. selon l'étape 1, je n'ai besoin nulle part ailleurs d'avoir les variables d'environnement du terminal SYMBOL_VOLUME_MAX, SYMBOL_VOLUME_MIN,SYMBOL_VOLUME_STEP et la quantité de caractères dans SYMBOL_VOLUME_STEP - cela ne change pas pendant le fonctionnement du programme MQL

3. en partant des points 1 et 2, je peux encapsuler les méthodes d'ouverture/de fermeture/de négociation des ordres et les propriétés des ordres eux-mêmes dans une classe CDeal - je ne vais pas utiliser tout cela n'importe où ? - c.-à-d. que je peux les utiliser tous dans une même classe


pp 1-3 tout est soluble, mais... OK, maintenant vous m'avez aidé avec la statique, qu'il en soit ainsi, car il y a une aide, au moins une façon de justifier ma décision, maintenant le code est comme ceci

class Cdeal : public CObject
  {
private:
   static const double VolumeMAX;
   static const double VolumeMIN;
   static const double VolumeSTEP;
   static const int  VolumeDIGITS;
   static int        GetDigitsInVolumeStep();
   SSettingsForOrder m_set;
public:
                     Cdeal() { Print(__FUNCTION__,"VolumeMAX = ",VolumeMAX," , VolumeMIN = ",VolumeMIN," , VolumeSTEP = ",VolumeSTEP," , VolumeDIGITS = ",VolumeDIGITS); }
  };
//____________________________________________________________________
static int Cdeal::GetDigitsInVolumeStep()
  {
   long i=10000000,k=long(VolumeSTEP/0.0000001);
   int result=0;
   while(result<7 && k%i>0)
     {
      i/=10;
      result++;
     }
   Print(__FUNCTION__);
   return(result);
  }
//____________________________________________________________________
static const double Cdeal::VolumeMAX = ::SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
//____________________________________________________________________
static const double Cdeal::VolumeMIN = ::SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
//____________________________________________________________________
static const double Cdeal::VolumeSTEP = ::SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
//____________________________________________________________________
static const int Cdeal::VolumeDIGITS = Cdeal::GetDigitsInVolumeStep();
//+------------------------------------------------------------------+

J'ai créé 3 instances de Cdeal, je l'ai eu dans le journal :

2019.08.29 21:53:53.613 AnyGrid_v1.00 EURUSD,M30 : initialisé

2019.08.29 21:53:53.613 AnyGrid_v1.00 EURUSD,M30 : Cdeal::CdealVolumeMAX = 100000.0 , VolumeMIN = 0.01 , VolumeSTEP = 0.01 , VolumeDIGITS = 2

2019.08.29 21:53:53.613 AnyGrid_v1.00 EURUSD,M30 : Cdeal::CdealVolumeMAX = 100000.0 , VolumeMIN = 0.01 , VolumeSTEP = 0.01 , VolumeDIGITS = 2

2019.08.29 21:53:53.613 AnyGrid_v1.00 EURUSD,M30 : Cdeal::CdealVolumeMAX = 100000.0 , VolumeMIN = 0.01 , VolumeSTEP = 0.01 , VolumeDIGITS = 2

2019.08.29 21:53:53.613 AnyGrid_v1.00 EURUSD,M30 : Cdeal::GetDigitsInVolumeStep

Jusqu'à présent, tout a fonctionné comme prévu !


C'est-à-dire, maintenant il n'y a pas de sections de code répétées (appels) - c'est un code efficace, mais comment s'éloigner de l'utilisation de la fonction statique static int Cdeal::GetDigitsInVolumeStep() - dans la vidéo, l'auteur croit qu'il est possible d'écrire du code OOP sans fonctions statiques, je vois que non seulement c'est peu pratique, mais qu'il n'est pas toujours possible de tout utiliser, à propos des méthodes Get et Set - très probablement je m'en passerai, je verrai plus tard


Vladimir Simakov:
L'option du champ statique présente un énorme inconvénient. Vous ne pouvez pas avoir des valeurs différentes de ce champ dans différentes instances de la classe.

Oui, merci, je le sais, le but est juste d'obtenir un code efficace sans variables excessives et sans utilisation inutile de la mémoire.



Je n'ai toujours pas résolu la question :comment éviter d'utiliser la fonction statique static int Cdeal::GetDigitsInVolumeStep()

 
Igor Makanu:

Voici un aperçu de ma classe, qui devrait initialiser les champs une fois avec des valeurs constantes, cela semble fonctionner comme prévu :

S'agit-il uniquement d'une classe de test ou allez-vous vraiment l'utiliser ?
Si c'est la seconde, vous ne devriez pas le faire de cette façon. Les variables statiques ne sont pas réinitialisées lorsque le symbole change, pour autant que je m'en souvienne.
Et en général, ce n'est pas une bonne idée d'initialiser les statiques constantes avec des valeurs externes, qui ne sont pas nécessairement disponibles au moment de l'initialisation.