Вопросы по ООП в MQL5 - страница 20

 
Koldun Zloy:
Статическая переменная, она и без наследования будет одна на все экземпляры.

проверил, ну да! все проще оказалось!

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

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

вижу, что переменную Language всего один раз инициализировал, т.е. это более простое решение

Спасибо!

 
Roman:

Подскажите, чем отличается ?
Создание объекта, или указателя, таким образом

от классического создания

Отличается тем, что в 1ом случае в C++ идентификатор класса CClass указывать необязательно 

 

вот набросал свой класс, который должен один раз инициализировать поля константными значениями, кажется все работает как задумано:

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

не нравятся мне 2 момента:

1. повторяю вызов SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP) - ибо не оговорен порядок инициализации, т.е. не факт, что у меня будет сначала инициализирована  VolumeSTEP , а лишь затем уже будет вызван  GetDigitsInVolumeStep()

2. хотелось бы избавиться от  использования статического метода static int        GetDigitsInVolumeStep() - насмотрелся видео на ютубе, что в чистом ООП не гоже использовать статические методы, вот борюсь с ветряными мельницами 

ссылки на видео, он одинаковы по сути https://youtu.be/lfdAwl3-X_c и  https://youtu.be/zME4SOCHT0I 


как бы вот эти 2 момента, которые мне не нравятся по другому переписать ?

 
Igor Makanu:

1. повторяю вызов SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP) - ибо не оговорен порядок инициализации, т.е. не факт, что у меня будет сначала инициализирована  VolumeSTEP , а лишь затем уже будет вызван  GetDigitsInVolumeStep()

1. т.е. боитесь, что порядок инициализации статиков неопределён? Вообще это не так, в плюсах инициализация в порядке определения в коде. Так что не парьтесь, сначала VolumeSTEP, а затем VolumeDIGITS.

 
Vict:

1. т.е. боитесь, что порядок инициализации статиков неопределён? Вообще это не так, в плюсах инициализация в порядке определения в коде. Так что не парьтесь, сначала VolumeSTEP, а затем VolumeDIGITS.

да, не то что боюсь, скажем предохраняюсь, я считаю,что код должен иметь хоть какую гарантию от изменения поведения компиляции - в общем ДА 

ЗЫ: тут в общем почему топик который раз апаю за день - хочу увидеть насколько реально сделать что то как в видео автор Егор рассказывает, пока сомневаюсь, что получится что то эффективное - сейчас вот уже и статик методы использую, да и с инициализацией уже некие сомнения появились

 
Vict:

1. т.е. боитесь, что порядок инициализации статиков неопределён? Вообще это не так, в плюсах инициализация в порядке определения в коде. Так что не парьтесь, сначала VolumeSTEP, а затем VolumeDIGITS. 

В MQL тоже

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

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

да, не то что боюсь, скажем предохраняюсь, я считаю,что код должен иметь хоть какую гарантию от изменения поведения компиляции - в общем ДА 

ЗЫ: тут в общем почему топик который раз апаю за день - хочу увидеть насколько реально сделать что то как в видео автор Егор рассказывает, пока сомневаюсь, что получится что то эффективное - сейчас вот уже и статик методы использую, да и с инициализацией уже некие сомнения появились

#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 

Пользоваться как-то так:

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

А в коде так:

CTradeConst* tradeConst=new CTradeConst;
CExampe* exsample[10];
for (int i=0;i<10;example[i++]=new CExample(_Symbol,tradeConst));
 
Вариант со static полем имеет один огромный минус. Вы не сможете иметь разные значения этого поля в разных экземплярах этого класса.
 
Vladimir Simakov:

Пользоваться как-то так:

А в коде так:

спс, немного не ту цель ставлю, так  я могу сделать

тут в общем что хочу добиться:

1. класс CDeal - самостоятельный, он открывает/закрывает/сопровождает свой ордер по одной стратегии - стратегии это перечисление, чтобы в оптимизаторе прокрутить микс стратегий

2. исходя из пп №1  получается, что мне не нужно больше нигде иметь переменные окружения терминала SYMBOL_VOLUME_MAX, SYMBOL_VOLUME_MIN,  SYMBOL_VOLUME_STEP и кол-во знаков в SYMBOL_VOLUME_STEP - это не изменяется в ходе работы MQL-программы

3. исходя из пп №1 и №2 - я могу инкапсулировать методы открытия/закрытия/трейлинга ордера и сами свойства ордера в один класс CDeal - я же нигде в дальнейшем не собираюсь использовать все это? - значит могу все в один класс обернуть


пп 1-3 все решаемо, НО.. ОК, вот со статиками помогли, пусть так ибо есть справка, хоть чем то свое решение можно обосновать, теперь код такой:

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

создал 3 экземпляра Cdeal, получил в логе:

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

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

пока все работает как и задумано!


т.е. сейчас нет участков повторяющегося кода (вызовов) - это эффективный код, НО как уйти от использования статической функции static int Cdeal::GetDigitsInVolumeStep() - по сюжету видео, автор считает что возможно без статических функций  писать код ООП, я пока вижу, что это мало того, что неудобно, так и не всегда это все и возможно использовать, про методы Get и Set - скорее всего обойдусь без них, дальше видно будет


Vladimir Simakov:
Вариант со static полем имеет один огромный минус. Вы не сможете иметь разные значения этого поля в разных экземплярах этого класса.

да, спс, я знаю это, задача как раз и получить эффективный код без лишних переменных и лишнего использования памяти



пока остался не решенный вопрос: как уйти от использования статической функции static int Cdeal::GetDigitsInVolumeStep() 

 
Igor Makanu:

вот набросал свой класс, который должен один раз инициализировать поля константными значениями, кажется все работает как задумано:

Это чисто тестовый класс или реально собираетесь его использовать?   
Если второе, то так делать не стоит.  Статические переменные не переинициализируются при смене символа, насколько я помню.
Да и вообще, иницилизировать константые статики некими внешними значениями, которые не факт что будут доступны на момент инициализации - не лучшая идея.