关于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类返回关于 的信息 ,符号的数字,并检查批次的错误,以及许多其他我工作需要的东西,包括在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;
  }
//+------------------------------------------------------------------+


你的课90%都是多余的。只有两个函数执行主要工作,这两个函数是openorders tip 为什么你用Sel、Buy SelStop等,而事实上它们都只是调用Openorders?此外,订单类型是以int形式传递的,所以它不受保护。你最好使用你自己的枚举或者标准的ENUM_ORDER_TYPE 来代替int。而且一般来说,你最好永远不要使用神奇的数字 "1"、"2 "等,只使用枚举。这将防止你向函数发送左边的订单值。开放边界函数本身太大。很明显,它由两个部分组成,即进行交易的部分和检查条件的部分。他们中的每一个人都应该作为一个独立的私人功能。

这是一个好的开始,但仍有很多东西需要学习。提示函数最好改写如下。

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


需要哪些具体内容?同样的原则在任何地方都适用:一切都必须尽可能简单。你不必为了进入荒野而进入荒野。如果一个问题可以简单解决,就应该简单解决。

如果程序需要动态地处理对象:在程序运行过程中创建、删除,就需要动态指针。如果你事先知道程序中需要哪些对象以及有多少对象,你就不需要动态指针。但除了有这么多对象时,通过new在一个循环中创建它们更容易。

在需要动态类型识别的复杂对象转换中,指针是不可缺少的。