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


この2点をどう書き換えたらいいのでしょうか?

 
Igor Makanu:

1. SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP)の呼び出しを繰り返す- 初期化の順序が指定されていないため、つまり VolumeSTEP を最初に初期化して、それからGetDigitsInVolumeStep() を呼び出すかどうかはわからない。

1.すなわち、静電容量の初期化順序が 不定であることを恐れているのでしょうか?実はそうではなく、プラスはコードで定義された順番に初期化されるのです。 だから、汗をかかないで、まずVolumeSTEP、そしてVolumeDIGITS。

 
Vict:

1.静電容量の初期化順序が 未定義であることを恐れているのですね。実はそうではなく、プラスでは初期化はコードで定義された順に行われるのです。だから、汗をかかないで、まずVolumeSTEP、そしてVolumeDIGITS。

そうですね、恐れているわけではなく、仮に保護されているとして、コンパイルの動作の変化に対して少なくとも何らかの保証がコードにあるべきだと考えています - 一般的にYES

ZS:ここで一般的に、なぜ一日の最初の時間のためのトピック - 私はビデオ著者のエゴールの ように何かを作るためにどのように現実的な見たい、私は我々が効果的な何かを得ることを疑いながら、言う- 今私は静的なメソッドを使用している、と初期化はすでにいくつかの疑問が登場しています。

 
Vict:

1.すなわち、静止画の初期化順序が 不定であることを恐れているのでしょうか?実はそうではなく、プラスはコードで定義された順番に初期化されるのです。だから、汗をかかないで、まずVolumeSTEP、そしてVolumeDIGITS。

MQLでも。

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

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

そうですね、恐れているわけではなく、仮に保護されているとして、コンパイルの動作の変化に対して少なくとも何らかの保証がコードにあるべきだと考えています - 一般的にYES

ZS:ここで一般的に、なぜ一日の最初の時間のためのトピック - 私は我々が効果的な何かを得ることを疑うが、ビデオの著者エゴールの ように何かを作るためにどのように現実的な見たい - 今私は静的なメソッドを使用している、と初期化はすでにいくつかの疑問が登場します。

#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クラスはスタンドアロンで、1つのストラテジーによってオープン/クローズ/オーダーを制御します。ストラテジーは列挙されるので、オプティマイザはストラテジーの組み合わせをスクロールできます

2. ステップ1によると、ターミナル環境変数SYMBOL_VOLUME_MAX, SYMBOL_VOLUME_MIN,SYMBOL_VOLUME_STEP と SYMBOL_VOLUME_STEP の文字数はどこにも必要ない - MQLプログラム動作中には変更されない。

3. 項目 1 と 2 から始めて、注文のオープン/クローズ/取引メソッドと注文プロパティ自体を 1 つのクラス CDeal にカプセル化することができます - 私はこのすべてをどこかに使用するつもりはないのですか?- つまり、1つのクラスですべてを使用することができます。


pp 1-3 全てが解決可能です、しかし... OK、今あなたは静力学で私を助けてくれました、そうであって欲しい、少なくとも私の決定を正当化する一つの方法があるのですから、今コードは次のようになります。

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

Cdealのインスタンスを3つ作成し、ログを取得しました。

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

今のところ、すべて計画通りに動いています


すなわち、今、繰り返されるコード(呼び出し)のセクションはありません - それは効率的なコードですが、どのように静的な関数の使用から逃れるために静的なint Cdeal::GetDigitsInVolumeStep() - ビデオでは、著者はそれが静的関数なしでOOPコードを書くことが可能と信じて、私はそれが不便であるばかりか、常にすべてを使用していないことがわかります、約ゲットとセットメソッド - おそらく私はそれらなしで行います、私は後で見るでしょう。


ウラジミール・シマコフ
スタティック・フィールド・オプションには、ひとつ大きな欠点があります。このフィールドは、クラスの異なるインスタンスで異なる値を持つことはできません。

はい、ありがとうございます、わかっています。目的は、不要な変数や不要なメモリを使用せずに効率的なコードを作成することです



静的関数 static int Cdeal::GetDigitsInVolumeStep() の使用を避けるには どうしたらよいか、という疑問はまだ解決していません。

 
Igor Makanu:

以下は私のクラスの概要ですが、フィールドを定数値で一度初期化する必要がありますが、意図したとおりに動作しているようです。

純粋にテスト用クラスなのか、本当に使うのか?
2つ目なら、そのやり方はやめた方がいいです。静的 変数は、私の記憶では、シンボルが変わっても再初期化されません。
また、一般に、定数静止画を外部値で初期化することは、初期化時に必ずしも利用できるわけではありません。