Domande su OOP (programmazione orientata agli oggetti) - pagina 5

 
VOLDEMAR:

Ora ho riprogettato la mia classe

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);
  }
E ha aggiunto l'eredità ... (sospetto di essermi sbagliato) dalla classe vr_MarketInfo

La classe vr_MarketInfo restituisce informazioni su Point, Digits per il simbolo e controlla il lotto per gli errori, e molte altre cose di cui ho bisogno per il lavoro tra cui tenere un registro in Excel e su un grafico

Quando si usa un metodo come sopra, quando si lavora in Primer.Primer.Primer() viene dato un elenco

Vorrei fare qualcosa di più abbreviato...

Dov'è l'eredità? Qual è lo scopo del puntatore?

 
Zhunko:

Dov'è l'eredità? Qual è lo scopo del puntatore?


Scrivere un libro di testo su MQL4+. Cooperate, intenditori, e scrivetelo. 50 dollari :)
 
In effetti, il libro di testo e la documentazione non sono molto specifici sull'uso dei puntatori o del nuovo operatore. Possiamo indovinare o aspettare che il tempo passi. O quando qualcuno dice accidentalmente qualcosa da qualche parte. Sono scioccato da come funzionano le cose. È anche interessante che a parte me e il topicstarter VLadimir nessuno sembra aver bisogno di qualcosa. Anche se continuo a credere che molte persone non capiscono questo argomento. Ed è per questo che non si fanno queste domande...
 
tara:

Scrivere un libro di testo su MQL4+. Cooperate, intenditori, e scrivetelo. 50 dollari :)

Tutto è stato scritto molto tempo fa.

MQL4 == C++ con leggere limitazioni.

 
hoz:
Di fatto, né il manuale, né la documentazione offrono alcuno specifico su come usare i puntatori, o il nuovo operatore. Possiamo indovinare o aspettare che il tempo passi. O quando qualcuno dice accidentalmente qualcosa da qualche parte. Sono scioccato da come succede. È anche interessante che a parte me e il topicstarter VLadimir nessuno sembra aver bisogno di qualcosa. Anche se continuo a credere che molte persone non capiscono questo argomento. Ed è per questo che non indagano su tali questioni...


Di che tipo di specifiche avete bisogno? Un principio si applica ovunque: mantenere le cose il più semplice possibile. Non entrare nel vivo delle cose solo per essere nel vivo delle cose. Se un problema può essere risolto semplicemente, deve essere risolto semplicemente.

I puntatori dinamici sono necessari se il vostro programma ha bisogno di lavorare dinamicamente con gli oggetti: creare, cancellare durante l'esecuzione del programma. Se sapete in anticipo quali e quanti oggetti sono necessari nel programma, non avete bisogno di puntatori dinamici. Ma a meno che non abbiate molti oggetti, potete semplicemente crearli in un ciclo con new.


 
VOLDEMAR:
Io per esempio trovo difficile imparare la teoria, mostratemi un esempio e descrivete come le funzioni definiscono cerchio, quadrato, trapezio o triangolo.

Uno degli articoli linkati nel primo post ha questo esempio.

Una classe base con un metodo virtuale. Il discendente ha un metodo con lo stesso nome, in cui vengono fatti i calcoli.

 
VOLDEMAR:
Per me è difficile imparare la teoria, mostratemi un esempio e descrivete come le funzioni definiscono un cerchio, un quadrato, un trapezio o un triangolo.


Lascio il trapezio e il triangolo al mio lavoro:

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

I puntatori dinamici sono necessari se il programma ha bisogno di lavorare dinamicamente con gli oggetti: crearli, cancellarli nel processo di funzionamento del programma. Se sapete in anticipo quali e quanti oggetti saranno necessari nel programma, non avete bisogno di puntatori dinamici. Ma a meno che non abbiate molti oggetti, è più facile crearli in un ciclo con new.

Esattamente! E anche in questo caso si può fare a meno dei puntatori.
 
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;
  }
//+------------------------------------------------------------------+


La vostra classe è ridondante al 90%. Solo due funzioni eseguono il lavoro principale, queste sono openorders e tip Perché usate Sel, Buy SelStop, etc., quando in realtà tutte chiamano semplicemente Openorders? Inoltre, il tipo di ordine è passato come int, quindi non è protetto. Invece di int è meglio che usiate la vostra enumerazione o lo standard ENUM_ORDER_TYPE. E in generale, è meglio non usare mai i numeri magici "1", "2" ecc. Questo vi impedirà di inviare il valore dell'ordine sinistro alla funzione. La stessa funzione Openorders è troppo grande. Ovviamente, consiste di due blocchi, il blocco di fare un accordo e il blocco di verificare le condizioni. Ognuno di loro dovrebbe essere come una funzione privata separata.

È un buon inizio, ma c'è ancora molto da imparare. La funzione di punta sarebbe meglio riscritta come segue:

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


Quali specifiche sono necessarie? Lo stesso principio si applica ovunque: tutto deve essere fatto nel modo più semplice possibile. Non c'è bisogno di andare nel deserto solo per essere nel deserto. Se un problema può essere risolto semplicemente, dovrebbe essere risolto semplicemente.

I puntatori dinamici sono necessari se il programma ha bisogno di lavorare dinamicamente con gli oggetti: creazione, cancellazione durante il funzionamento del programma. Se sapete in anticipo quali e quanti oggetti saranno necessari nel programma, non avete bisogno di puntatori dinamici. Ma a parte quando ci sono tanti oggetti, è più facile crearli in un ciclo tramite new.

I puntatori sono indispensabili per le conversioni di oggetti complessi in cui è richiesta l'identificazione dinamica del tipo.
Motivazione: