MQL5中的OOP问题 - 页 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: 已初始化

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:

请告诉我,这有什么不同?
以这种方式创建一个对象,或指针

来自经典创作

不同的是,在第一种情况下,你不需要在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() - 我在youtube上看到一个视频,说在纯OOP中不应该使用静态方法,现在我正在和风车斗争

视频的链接,它基本上是相同的https://youtu.be/lfdAwl3-X_c 和https://youtu.be/zME4SOCHT0I


我怎样才能以不同的方式改写我不喜欢的这两点呢?

 
Igor Makanu:

1.我重复调用 SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP) - 因为没有指定初始化的顺序,也就是说,不能确定我是否会先初始化VolumeSTEP,然后才调用GetDigitsInVolumeStep()

1.也就是说,你是否担心静力学初始化的顺序 未被定义?实际上不是的,正数在代码中是按照定义的顺序初始化的。 所以不要紧张,首先是VolumeSTEP,然后是VolumeDIGITS。

 
Vict:

1.所以你担心静力学初始化的顺序 是未定义的?实际上并非如此,在pluses中,初始化是按照代码中的定义顺序进行的。所以不要紧张,首先是VolumeSTEP,然后是VolumeDIGITS。

是的,不是说我害怕,就说我被保护了,我相信代码至少应该有一些保证,以防止编译行为的改变--一般来说是的

ZS:在这里,一般来说,为什么这个话题第一次出现在一天 - 我想看看如何现实地做出像视频作者Egor所说的 东西,而我怀疑我们得到有效的东西 - 现在我正在使用静态方法,并与初始化已经出现一些疑问

 
Vict:

1.也就是说,你是否担心静力学的初始化顺序 没有确定?实际上不是的,加号在代码中是按照定义的顺序初始化的。所以不要紧张,首先是VolumeSTEP,然后是VolumeDIGITS。

在MQL中也是如此。

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

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

是的,不是说我害怕,就说我被保护了,我相信代码至少应该有一些保证,以防止编译行为的变化--一般来说是的

ZS:在这里,一般来说,为什么这个话题第一次出现在一天 - 我想看看如何现实地做出像视频作者Egor所说的 东西,而我怀疑我们会得到有效的东西 - 现在我正在使用静态方法,并与初始化已经出现一些疑问

#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));
 
静态场选项有一个巨大的缺点。在类的不同实例中,你不能有不同的这个字段的值。
 
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: 已初始化

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()-- 在视频中,作者认为写OOP代码可以不使用静态函数,我看到不仅不方便,而且不一定能使用所有东西,关于Get和Set方法--很可能我将没有它们,我以后会看到。


弗拉基米尔-西马科夫
静态场选项有一个巨大的缺点。在类的不同实例中,你不能有不同的这个字段的值。

是的,谢谢,我知道,目的只是为了得到一个高效的代码,没有多余的变量和不必要的内存使用。



我仍然没有解决的问题是:如何避免使用静态函数static int Cdeal::GetDigitsInVolumeStep()。

 
Igor Makanu:

这是我的类的大纲,它应该用常量值初始化一次字段,它似乎按计划工作。

这纯粹是一个测试类,还是你真的要使用它?
如果是第二种情况,你不应该这样做。 在我的记忆中,当符号发生变化时,静态变量 不会被重新初始化。
而且,一般来说,用外部值来初始化常量静力学并不是一个好主意,因为在初始化的时候不一定有这些值。