Preguntas de POO (Programación Orientada a Objetos) - página 5

 
VOLDEMAR:

Ahora he rediseñado mi clase

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);
  }
Y añadió la herencia ... ( sospecho que puedo estar equivocado ) de la clase vr_MarketInfo

La clase vr_MarketInfo devuelve información sobre el punto, los dígitos del símbolo y comprueba el lote en busca de errores, y muchas otras cosas que necesito para el trabajo, incluyendo el mantenimiento de un registro en Excel y en un gráfico

Cuando se utiliza un método como el anterior se da una lista cuando se trabaja en Primer.Primer.Primer()

Me gustaría hacer algo más abreviado...

¿Dónde está la herencia? ¿Para qué sirve el puntero?

 
Zhunko:

¿Dónde está la herencia? ¿Para qué sirve el puntero?


Escriba un libro de texto sobre MQL4+. Cooperen, conocedores, y escríbanlo. 50 dólares :)
 
De hecho, el libro de texto y la documentación no son muy específicos sobre el uso de punteros o del nuevo operador. Podemos adivinar o esperar a que pase el tiempo. O cuando alguien dice algo accidentalmente en algún lugar. Me sorprende cómo funcionan las cosas. También es interesante que salvo yo y el tópico VLadimir nadie parece necesitar nada. Aunque sigo creyendo que mucha gente no entiende este tema. Y por eso no se meten en esas cuestiones...
 
tara:

Escriba un libro de texto sobre MQL4+. Cooperen, conocedores, y escríbanlo. 50 dólares :)

Todo fue escrito hace mucho tiempo.

MQL4 == C++ con ligeras limitaciones.

 
hoz:
De hecho, ni el manual ni la documentación ofrecen detalles sobre cómo utilizar los punteros o el nuevo operador. Podemos adivinar o esperar a que pase el tiempo. O cuando alguien dice algo accidentalmente en algún lugar. Estoy sorprendido de cómo funcionan las cosas. También es interesante que salvo yo y el tópico VLadimir nadie parece necesitar nada. Aunque sigo creyendo que mucha gente no entiende este tema. Y por eso no se meten en esas cuestiones...


¿Qué tipo de detalles necesita? Hay un principio que se aplica en todas partes: mantener las cosas lo más sencillas posible. No te metas en el meollo de la cuestión sólo por estar en el meollo de la cuestión. Si un problema puede resolverse de forma sencilla, debe resolverse de forma sencilla.

Los punteros dinámicos son necesarios si su programa necesita trabajar dinámicamente con objetos: crear, eliminar durante la ejecución del programa. Si sabes de antemano cuáles y cuántos objetos se necesitan en el programa, no necesitas punteros dinámicos. Pero a menos que tengas muchos objetos, puedes simplemente crearlos en un bucle con new.


 
VOLDEMAR:
A mí por ejemplo me cuesta aprender la teoría, muéstrame un ejemplo y describe cómo las funciones definen el círculo, el cuadrado, el trapecio o el triángulo.

Uno de los artículos enlazados en el primer post tiene este ejemplo.

Una clase base con un método virtual. El descendiente tiene un método con el mismo nombre, en el que se realizan los cálculos.

 
VOLDEMAR:
A mí me cuesta aprender la teoría, muéstrame un ejemplo y describe cómo las funciones definen un círculo, un cuadrado, un trapecio o un triángulo...


Dejo el trapecio y el triángulo para mi propio trabajo:

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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:

Los punteros dinámicos son necesarios si el programa necesita trabajar dinámicamente con objetos: crearlos, borrarlos durante el funcionamiento del programa. Si se sabe de antemano cuáles y cuántos objetos se van a necesitar en el programa, no se necesitan punteros dinámicos. Pero a menos que tengas muchos objetos, es más fácil crearlos en un bucle con new.

¡Exactamente! E incluso en ese caso se puede prescindir de los punteros.
 
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;
  }
//+------------------------------------------------------------------+


Su clase es redundante en un 90%. Sólo dos funciones realizan el trabajo principal, éstas son openorders y consejo ¿Por qué se utiliza Sel, Buy SelStop, etc., cuando en realidad todas ellas sólo llaman a Openorders? Además, el tipo de orden se pasa como int, por lo que no está protegido. En lugar de int, es mejor utilizar su propia enumeración o el estándar ENUM_ORDER_TYPE. Y, en general, es mejor no utilizar nunca los números mágicos "1", "2", etc., sólo las enumeraciones. Esto evitará que envíe el valor de la orden izquierda a la función. La propia función de Openorders es demasiado grande. Obviamente, consta de dos bloques, el bloque de hacer un trato y el bloque de comprobar las condiciones. Cada uno de ellos debe ser como una función privada separada.

Es un buen comienzo, pero todavía hay mucho que aprender. La función de la punta se reescribiría mejor de la siguiente manera:

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


¿Qué detalles se necesitan? El mismo principio se aplica en todas partes: todo debe hacerse de la forma más sencilla posible. No hay que ir al desierto sólo para estar en el desierto. Si un problema puede resolverse de forma sencilla, debe resolverse de forma sencilla.

Los punteros dinámicos son necesarios si el programa necesita trabajar dinámicamente con los objetos: crear, borrar durante el funcionamiento del programa. Si se sabe de antemano cuáles y cuántos objetos se van a necesitar en el programa, no se necesitan punteros dinámicos. Pero excepto cuando hay tantos objetos, es más fácil crearlos en un bucle mediante new.

Los punteros son indispensables para las conversiones complejas de objetos en las que se requiere una identificación dinámica del tipo.