OOP(オブジェクト指向プログラミング)に関する質問 - ページ 5

 
VOLDEMAR:

このたび、授業の内容を一新しました

class vr_trade
  {
private:
   int               openorders(string sy,int typ,double lot,double price);
   string            tip(int typ);
   int               m_magic;
   int               m_slip;
public:
   int               Buy(string sy,double lot);
   int               Sel(string sy,double lot);
   int               BuyLimit(string sy,double lot,double price);
   int               SelLimit(string sy,double lot,double price);
   int               BuyStop(string sy,double lot,double price);
   int               SelStop(string sy,double lot,double price);
   void              MagSlip(int mag=-1,int slip=0);
   vr_MarketInfo    *Log;
                     vr_trade();
                    ~vr_trade();
  };
MqlTick st;
//+------------------------------------------------------------------+
vr_trade:: vr_trade()
  {
   Log=new vr_MarketInfo;
   MagSlip(-1,0);
  }
そして、相続を追加した・・・。(vr_MarketInfo クラスから(間違っているかもしれませんが)。

vr_MarketInfoクラスは PointやシンボルのDigitsに関する 情報を返し、ロットにエラーがないかをチェックするほか、Excelやチャート上でログを残すなど、仕事で必要なさまざまな 情報を提供する。

上記のようなメソッドを使用した場合、Primer.Primer.Primer()で作業すると、リストが表示されます。

もっと省略されたものをやりたいのですが...。

遺産はどこにある?ポインターは何のためにあるのか?

 
Zhunko:

遺産はどこにある?ポインターの意味は何ですか?


MQL4+の教科書を書く。目利きの皆さん、協力して書いてください。50ドル :)
 
実際、教科書やドキュメントには、ポインタの使い方や new 演算子についてあまり具体的に書かれていません。当てるか、天候が過ぎるのを待つか、どちらかです。あるいは、誰かがどこかでうっかり言ってしまったとき。その仕組みにショックを受けています。また、私と話題提供者のVLadimirを除いて、誰も何も必要としていないようなのが面白いですね。とはいえ、このテーマを理解していない人はまだまだ多いと思っています。だから、そんな質問には答えてくれないんだ......。
 
tara:

MQL4+の教科書を書く。目利きの皆さん、協力して書いてください。50ドル :)

すべては、ずっと前に書かれたものです。

MQL4 == C++に若干の制限あり。

 
hoz:
実は、ポインターの 使い方や新しい 演算子については、マニュアルにもドキュメントにも、具体的なことは書かれていません。当てるか、天候が過ぎるのを待つか、どちらかです。あるいは、誰かがどこかでうっかり言ってしまったとき。どうしてこうなるのか、ショックです。また、私と話題提供者のVLadimirを除いて、誰も何も必要としていないようなのが面白いですね。とはいえ、このテーマを理解していない人はまだまだ多いと思っています。そして、そのような質問を詮索しないのは、そのためです...


どのような仕様が必要なのでしょうか?物事をできるだけシンプルにする、という原則はどこにでも当てはまります。ただ、物事の真っ只中に入ってはいけない。シンプルに解決できる問題は、シンプルに解決しなければならない。

動的ポインターは、プログラムの実行中にオブジェクトを 動的に操作 する必要がある場合に必要とされます 作成、削除。プログラム中にどのオブジェクトがいくつ必要かがあらかじめ分かっていれば、動的ポインタは必要ない。しかし、大量のオブジェクトがない限り、単純にnewでループして作成することができます。


 
VOLDEMAR:
例えば、円、正方形、台形、三角形が関数でどのように定義されるのか、例を示して説明してくださいと言われても、理論を学ぶのは難しいです。

最初の記事でリンクされている記事の中に、こんな例があります。

仮想メソッドを持つ基底クラス。子孫は同名のメソッドを持ち、その中で計算が行われる。

 
VOLDEMAR:
私は、理論を学び、例を示し、関数が円、正方形、台形、三角形をどのように定義するかを説明するのは難しいと感じています......?


台形と三角形は、自分の作品に残しておきます。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CShape
  {
  
public:
   virtual string Type()      { return(""); }
   virtual double Perimeter() { return(-1); }
   virtual double Square()    { return(-1); }
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CCircle : public CShape
  {
   double         m_r;
  
public:
                  CCircle(double r):m_r(r) { }
   virtual string Type()      { return("circle");     }
   virtual double Perimeter() { return(2*M_PI*m_r);   }
   virtual double Square()    { return(M_PI*m_r*m_r); }
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CRectangle : public CShape
  {
   double         m_a;   
   double         m_b;
   
public:
                  CRectangle(double a,double b):m_a(a),m_b(b) { }
   virtual string Type()      { return("rectangle");  }
   virtual double Perimeter() { return(m_a*2+m_b*2);  }
   virtual double Square()    { return(m_a*m_b);      }   
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   CShape *shape[10];
//--- создаём объекты
   for(int n=0;n<10;n++)
     {
      if((MathRand()&1)==1)
         shape[n]=new CCircle(MathRand()%10+1);
      else
         shape[n]=new CRectangle(MathRand()%10+1,MathRand()%10+1);
     }
//--- выводим данные по объектам
   for(int n=0;n<10;n++)
      PrintFormat("%s p=%.3f s=%.3f",shape[n].Type(),shape[n].Perimeter(),shape[n].Square());
//--- удаляем объекты
   for(int n=0;n<10;n++)
      delete shape[n];
  }
//+------------------------------------------------------------------+
 
Integer:

動的ポインターは、プログラムが動的にオブジェクトを操作する必要がある場合に必要とされるものです。プログラム中にどのオブジェクトがいくつ必要になるかがあらかじめ分かっていれば、動的ポインタは必要ない。しかし、オブジェクトの数が多くない限り、newでループして作成する方が簡単です。

そのとおりです。また、その場合でもポインターはなくても大丈夫です。
 
VOLDEMAR:
#property strict
input int Slip=30;
input int Magic=0;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
class vr_trade
  {
private:
   int               openorders(string sy,int typ,double lot,double price);
   string            tip(int typ);
public:
   int               Buy(string sy,double lot);
   int               Sel(string sy,double lot);
   int               BuyLimit(string sy,double lot, double price);
   int               SelLimit(string sy,double lot, double price);
   int               BuyStop(string sy,double lot, double price);
   int               SelStop(string sy,double lot, double price);
                     vr_trade(){}
                    ~vr_trade(){}
  };
MqlTick st;
vr_trade trade;
//+------------------------------------------------------------------+
void OnTick()
  {
trade.Buy("EURUSD",0.01); // Пример открытия позиции возвращающей тиккет ордера.
  }
//+------------------------------------------------------------------+  
int vr_trade :: Buy(string sy,double lot)
{
return openorders(sy,0,lot);
}
//+------------------------------------------------------------------+  
int vr_trade :: Sel(string sy,double lot)
{
return openorders(sy,1,lot);
}
//+------------------------------------------------------------------+  
int vr_trade :: BuyLimit(string sy,double lot, double price)
{
return openorders(sy,2,lot,price);
}
//+------------------------------------------------------------------+  
int vr_trade :: SelLimit(string sy,double lot, double price)
{
return openorders(sy,3,lot,price);
}
//+------------------------------------------------------------------+  
int vr_trade :: BuyStop(string sy,double lot, double price)
{
return openorders(sy,4,lot,price);
}
//+------------------------------------------------------------------+  
int vr_trade :: SelStop(string sy,double lot, double price)
{
return openorders(sy,5,lot,price);
}
//+------------------------------------------------------------------+
int vr_trade :: openorders(string sy="",int typ=0,double lot=0,double price=0)
  {
   int tik=-2;
   double di=NormalizeDouble(500*_Point,_Digits);
   if(sy==""){sy=_Symbol;Print("Установлен символ текущего графика ",sy);}
   if(lot<MarketInfo(sy,MODE_MINLOT)){lot=MarketInfo(sy,MODE_MINLOT); Print("Советник скорректировал лот ",lot);}
   if(!SymbolInfoTick(sy,st))Print("Не удалось прогрузить цены для символа ",sy);
   if(price==0)//Даблы так лучше не сравнивать.
     {
      if(typ==0)price=st.ask;
      if(typ==1)price=st.bid;
      if(typ==2)price=st.ask-di;
      if(typ==3)price=st.bid+di;
      if(typ==4)price=st.ask+di;
      if(typ==5)price=st.bid-di;
     }
   if(IsTradeAllowed()==true)
     {
      RefreshRates();
      tik=OrderSend(sy,typ,lot,price,Slip,0,0,"",Magic,0,clrRed);
      if(tik>0)Print("Успешно открыт ордер Ticket ",tik," Typ ",tip(typ)," Symbol ",sy," Lot ",lot," Price ",price);
      else Print("Ошибка открытия ордера N",GetLastError());
     }
   else
      Print("Торговый поток занят");
   return tik;
  }
//+------------------------------------------------------------------+
string vr_trade :: tip(int typ ENUM_ORDER_TYPE type)
  {
   string txt="";
   switch(typ)
     {
      case 0: txt="BUY";        break;
      case 1: txt="SELL";       break;
      case 2: txt="BUY LIMIT";  break;
      case 3: txt="SELL LIMIT"; break;
      case 4: txt="BUY STOP";   break;
      case 5: txt="SELL STOP";  break;
      default : txt="Ошибка типа ордера";
     }
   return txt;
  }
//+------------------------------------------------------------------+


あなたのクラスは9割がた冗長です。メイン作業を行うのは2つの機能だけで、これらは openordersと tip なぜSelやBuy SelStopなどを使うのか、実際にはすべてOpenordersを呼び出すだけなのに。さらに、オーダー型はint型として渡されるため、protectedではありません。intの代わりに、独自の列挙型か標準のENUM_ORDER_TYPEを 使用した方がよいでしょう。また、一般に、マジックナンバー "1 "や "2 "などは絶対に使用しない方がよく、列挙のみ使用します。これにより、左のオーダー値を関数に送信することを防ぐことができます。Openordersの機能自体が大きすぎるのです。当然ながら、取引をするブロックと条件を確認するブロックの2つで構成されています。それぞれ独立したプライベートな機能としてあるべきものです。

良いスタートではありますが、まだまだ学ぶべきことはたくさんあります。チップ関数は、次のように書き換えた方が良いだろう。

string vr_trade::tip(ENUM_ORDER_TYPE orderType)
{
   return EnumToString(orderType);
}
 
Integer:


具体的にどのようなことが必要なのでしょうか?何事もできるだけシンプルに行うという原則は、どこでも同じです。荒野に行くだけではありません。シンプルに解決できる問題は、シンプルに解決すべきなのです。

動的ポインターは、プログラムが動作中にオブジェクトを作成したり削除したりと、動的に動作させる必要がある場合に必要となります。プログラム中にどのオブジェクトがいくつ必要になるかがあらかじめ分かっていれば、動的ポインタは必要ない。しかし、オブジェクトの数が多いとき以外は、newによるループで作成する方が簡単です。

ポインターは、動的な型識別が必要な複雑なオブジェクト変換には欠かせないものです。