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_chttps://youtu.be/zME4SOCHT0I 입니다.


내가 다르게 좋아하지 않는 이 2가지 점을 어떻게 다시 작성합니까?

 
Igor Makanu :

1. SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP) 호출을 반복합니다 . 초기화 순서가 지정되지 않았기 때문입니다. VolumeSTEP을 먼저 초기화한 다음 GetDigitsInVolumeStep() 이 호출된다는 사실이 아닙니다.

1. 즉 정적 초기화 순서 가 정의되지 않은 것이 두려우신가요? 일반적으로 그렇지 않습니다. 플러스에서 초기화는 코드에 정의된 순서대로 진행됩니다. 그러니 걱정하지 마세요. 먼저 VolumeSTEP을 사용하고 VolumeDIGITS를 사용하세요.

 
Vict :

1. 즉 정적 초기화 순서 가 정의되지 않은 것이 두려우신가요? 일반적으로 그렇지 않습니다. 플러스에서 초기화는 코드에 정의된 순서대로 진행됩니다. 그러니 걱정하지 마세요. 먼저 VolumeSTEP을 사용하고 VolumeDIGITS를 사용하세요.

예, 제가 두려워하는 것은 아닙니다. 제 자신을 보호하고 있다고 가정해 보겠습니다. 코드에는 컴파일 동작 변경에 대한 최소한의 보증이 있어야 한다고 생각합니다. 일반적으로 예

추신: 여기에서 일반적으로 하루에 한 번 이상 주제가 지불되는 이유 - 비디오에서와 같이 작업을 수행하는 것이 얼마나 현실적인지 알고 싶습니다. 저자 Yegor는 말합니다 , 하지만 효과적인 무언가가 나올지는 의심스럽습니다 - 지금 이미 정적 메서드를 사용하고 있으며 이미 초기화에 대한 의심이 나타납니다.

 
Vict :

1. 즉 정적 초기화 순서 가 정의되지 않은 것이 두려우신가요? 일반적으로 그렇지 않습니다. 플러스에서 초기화는 코드에 정의된 순서대로 진행됩니다. 그러니 걱정하지 마세요. 먼저 VolumeSTEP을 사용하고 VolumeDIGITS를 사용하세요.

MQL에서도

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

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

예, 제가 두려워하는 것은 아닙니다. 제 자신을 보호하고 있다고 가정해 보겠습니다. 코드에는 컴파일 동작 변경에 대한 최소한의 보증이 있어야 한다고 생각합니다. 일반적으로 예

추신: 일반적으로 여기에 내가 하루 동안 지불하는 주제가 있습니다. - 비디오에서와 같은 작업을 수행하는 것이 얼마나 현실적인지 알고 싶습니다. 저자 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 :

다음과 같이 사용하십시오.

그리고 다음과 같은 코드에서:

ATP, 조금 잘못된 목표를 설정하여 할 수 있습니다

달성하고자 하는 바는 다음과 같습니다.

1. CDeal 클래스는 독립적이며 하나의 전략에 따라 순서를 열고/닫고/동반합니다. 전략은 최적화 프로그램에서 혼합된 전략을 스크롤하기 위한 열거입니다.

2. 항목 #1을 기반으로 터미널 환경 변수 SYMBOL_VOLUME_MAX, SYMBOL_VOLUME_MIN, SYMBOL_VOLUME_STEP 및 SYMBOL_VOLUME_STEP의 문자 수를 갖는 데 다른 곳이 필요하지 않은 것으로 나타났습니다. 이것은 MQL 프로그램의 작동 중에 변경되지 않습니다.

3. 단락 #1 및 #2를 기반으로 - 주문을 열고/닫고/추적하는 방법과 주문 속성 자체를 하나의 CDeal 클래스로 캡슐화할 수 있습니다. - 앞으로 이 모든 것을 사용하지 않을 것입니다. ? - 모든 것을 하나의 클래스로 묶을 수 있도록


pp 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 메서드에 대해 이 모든 것을 항상 사용할 수 있는 것은 아닙니다. 볼거야


블라디미르 시마코프 :
정적 필드가 있는 옵션에는 한 가지 큰 단점이 있습니다. 이 클래스의 다른 인스턴스에서 이 필드에 대해 다른 값을 가질 수 없습니다.

네, ATP, 알고 있습니다. 작업은 불필요한 변수와 불필요한 메모리 사용 없이 효율적인 코드를 얻는 것뿐입니다.



질문이 해결되지 않을 때까지: 정적 함수 사용에서 벗어나는 방법 static int Cdeal::GetDigitsInVolumeStep()

 
Igor Makanu :

여기에 상수 값으로 필드를 한 번 초기화해야 하는 클래스를 스케치했는데 모든 것이 의도한 대로 작동하는 것 같습니다.

이것은 단지 테스트 클래스입니까 아니면 실제로 사용하시겠습니까?
후자라면 하지 말아야 합니다. 내가 기억하는 한 정적 변수 는 문자 변경 시 다시 초기화되지 않습니다.
그리고 일반적으로 초기화 시 사용할 수 있다는 사실이 아닌 일부 외부 값으로 상수 정적을 초기화하는 것은 좋은 생각이 아닙니다.