Fragen zu OOP in MQL5 - Seite 20

 
Koldun Zloy:
Statische Variable, so ist sie für alle Instanzen ohne Vererbung gleich.

Ich habe es überprüft, und ja, es war einfacher als das!

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

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

Ich sehe, dass die Variable Language nur einmal initialisiert wurde, d.h. dies ist eine einfachere Lösung

Ich danke Ihnen!

 
Roman:

Bitte sagen Sie mir, worin der Unterschied besteht?
Ein Objekt oder einen Zeiger auf diese Weiseerstellen

von der klassischen Schöpfung

Der Unterschied besteht darin, dass Sie im ersten Fall denCClass-Klassenbezeichner in C++ nicht angeben müssen.

 

Ich habe meine Klasse skizziert, die Felder einmal mit konstanten Werten initialisieren soll, und es scheint wie vorgesehen zu funktionieren:

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

Ich mag 2 Dinge nicht:

1. ich wiederhole den Aufruf von SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP) - weil die Reihenfolge der Initialisierung nicht festgelegt ist, d.h. es ist nicht sicher, dass VolumeSTEP zuerst initialisiert wird und erst dannGetDigitsInVolumeStep() aufgerufen wird

2. ich möchte die statische Methode static int GetDigitsInVolumeStep() loswerden - ich habe ein Video auf youtube gesehen, in dem gesagt wird, dass man in reinem OOP keine statischen Methoden verwenden sollte, und jetzt kämpfe ich gegen Windmühlen

der Link zum Video, es ist im Wesentlichen das gleichehttps://youtu.be/lfdAwl3-X_c undhttps://youtu.be/zME4SOCHT0I


Wie kann ich diese 2 Punkte, die mir nicht gefallen, anders formulieren?

 
Igor Makanu:

1. ich wiederhole den Aufruf von SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP) - weil die Reihenfolge der Initialisierung nicht festgelegt ist, d. h. es ist nicht sicher, dass zuerst VolumeSTEP initialisiert wird und erst dann GetDigitsInVolumeStep() aufgerufen wird

1. Haben Sie Angst, dass die Reihenfolge der Statikinitialisierung undefiniert ist? Eigentlich nicht, denn die Pluszeichen werden in der Reihenfolge der Definition im Code initialisiert. Also keine Panik, erst VolumeSTEP und dann VolumeDIGITS.

 
Vict:

1. Sie befürchten also, dass die Reihenfolge der Initialisierung der Statik undefiniert ist? Eigentlich ist es nicht so, in pluses Initialisierung ist in der Reihenfolge der Definition im Code. Also keine Panik, erst VolumeSTEP und dann VolumeDIGITS.

Ja, nicht, dass ich Angst hätte, sagen wir, ich bin geschützt, ich glaube, dass der Code zumindest eine gewisse Garantie gegen Änderungen im Kompilierungsverhalten haben sollte - im Allgemeinen JA

ZS: Hier im Allgemeinen, warum das Thema für die einmal am Tag apaed - ich will sehen, wie realistisch, um etwas wie in der Video-Autor Egor sagt, während ich bezweifle, dass wir etwas effektiv zu bekommen - jetzt bin ich mit statischen Methoden, und mit der Initialisierung sind bereits einige Zweifel erschienen

 
Vict:

1. Befürchten Sie, dass die Reihenfolge der Initialisierung der Statik undefiniert ist? Eigentlich nicht, denn die Pluszeichen werden in der Reihenfolge der Definition im Code initialisiert. Also keine Panik, erst VolumeSTEP und dann VolumeDIGITS.

Auch bei MQL.

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

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

Ja, nicht, dass ich Angst hätte, sagen wir, ich bin geschützt, ich glaube, dass der Code zumindest eine gewisse Garantie gegen Änderungen im Kompilierungsverhalten haben sollte - im Allgemeinen JA

ZS: hier im Allgemeinen, warum das Thema zum ersten Mal einen Tag - ich will sehen, wie realistisch, um etwas wie in dem Video Autor Egor sagt, während ich bezweifle, dass wir etwas effektiv zu bekommen - jetzt bin ich mit statischen Methoden, und mit der Initialisierung sind bereits einige Zweifel erschienen

#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 

Um es auf diese Weise zu verwenden:

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

Und in einem Code wie diesem:

CTradeConst* tradeConst=new CTradeConst;
CExampe* exsample[10];
for (int i=0;i<10;example[i++]=new CExample(_Symbol,tradeConst));
 
Die Option des statischen Feldes hat einen großen Nachteil. Sie können keine unterschiedlichen Werte für dieses Feld in verschiedenen Instanzen der Klasse haben.
 
Vladimir Simakov:

Verwenden Sie wie folgt:

Und im Code wie folgt:

Ups, ein kleiner Irrtum, das ist es, was ich tun kann

Ich möchte im Allgemeinen Folgendes erreichen:

1. die Klasse CDeal ist eigenständig, sie öffnet/schließt/steuert ihre Reihenfolge durch eine Strategie - die Strategien werden aufgezählt, so dass der Optimierer durch die Mischung der Strategien blättern kann

2. nach Schritt 1 brauche ich nirgendwo anders die Terminal-Umgebungsvariablen SYMBOL_VOLUME_MAX, SYMBOL_VOLUME_MIN,SYMBOL_VOLUME_STEP und die Anzahl der Zeichen in SYMBOL_VOLUME_STEP - sie ändern sich nicht während des MQL-Programmbetriebs

3. ausgehend von den Punkten 1 und 2 kann ich die Methoden zum Öffnen/Schließen/Handeln von Aufträgen und die Auftragseigenschaften selbst in einer Klasse CDeal kapseln - ich werde all dies nirgendwo verwenden? - d.h. ich kann sie alle in einer Klasse verwenden


pp 1-3 alles ist lösbar, aber... OK, jetzt hast du mir mit der Statik geholfen, lass es so sein, denn es gibt eine Hilfe, zumindest eine Möglichkeit, meine Entscheidung zu rechtfertigen, jetzt ist der Code wie folgt

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

Ich habe 3 Instanzen von Cdeal erstellt und es im Protokoll gefunden:

2019.08.29 21:53:53.613 AnyGrid_v1.00 EURUSD,M30: initialisiert

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

Bis jetzt hat alles wie geplant funktioniert!


D.h., jetzt gibt es keine Abschnitte mit wiederholtem Code (Aufrufe) - es ist ein effizienter Code, aber wie kommt man weg von der Verwendung der statischen Funktion static int Cdeal::GetDigitsInVolumeStep() - im Video glaubt der Autor, dass es möglich ist, OOP-Code ohne statische Funktionen zu schreiben, ich sehe, dass es nicht nur unbequem ist, sondern dass es nicht immer möglich ist, alles zu verwenden, über Get- und Set-Methoden - wahrscheinlich werde ich ohne sie auskommen, ich werde später sehen


Wladimir Simakow:
Die Option des statischen Feldes hat einen großen Nachteil. Sie können keine unterschiedlichen Werte für dieses Feld in verschiedenen Instanzen der Klasse haben.

Ja, danke, das weiß ich, der Zweck ist nur, einen effizienten Code ohne unnötige Variablen und unnötige Verwendung von Speicher zu erhalten



Ich habe die Frage immer noch nicht gelöst:Wie kann man vermeiden, die statische Funktion static int Cdeal::GetDigitsInVolumeStep()

 
Igor Makanu:

Hier ist ein Überblick über meine Klasse, die Felder einmal mit konstanten Werten initialisieren sollte, scheint es zu funktionieren wie beabsichtigt:

Handelt es sich um eine reine Testklasse oder wollen Sie sie wirklich nutzen?
Statische Variablen werden nicht neu initialisiert, wenn sich das Symbol ändert, so weit ich mich erinnere.
Und im Allgemeinen ist es keine gute Idee, konstante statische Werte mit externen Werten zu initialisieren, die zum Zeitpunkt der Initialisierung nicht unbedingt verfügbar sind.