Parlare dell'OLP nel salone - pagina 4

 
Dennis Kirichenko:

Buon punto. Sarebbe bello se gli argomenti fossero supportati da un codice piuttosto che solo bla, bla, bla.

Sostenere la cosa.

Ecco la mia classe CMyObject:

#include <Object.mqh>

// Перечисление, в котором должны указываться все объекты, которые могут быть пронаследованны от моего объекта
enum EMyObjectTypes
{
   MOT_BASE_OBJECT                              =  0001,          // Просто CObject - фактически, никогда не должен использоваться.
   MOT_STRUCT_WRAPPER                           =  0002,          // Неинициализированный CStructWrapper
   MOT_PRICE_POINT                              =  0003,          // Класс CPricePoint   
   MOT_PRICEIDX_POINT                           =  0004,          // Класс CPriceIdxPoint  
   MOT_WPRICEIDX_POINT                          =  0005,          // Класс CWPriceIdxPoint  
   MOT_WAVE_TRIANGLE_DATA                       =  0006,          // Класс CWaveTriangleData
   MOT_WAVE_TRIANGLE                            =  0007,          // Класс CWaveTriangle
   MOT_TRADERESULT_I                            =  0008,          // Класс CTradeResultI
   MOT_TRADERESULT                              =  0009,          // Класс CTradeResult

   // Тут еще куча типов объектов - для каждого класса, свой ID
           
   MOT_UNKNOWN                                  = -0001           // Неинициализированный объект.
};

/*

Класс СMyObject - потомок от СObject, несет функциональность именования.

*/

class CMyObject: public CObject
{
protected:
   EMyObjectTypes m_motType;
   int            m_iUDCreationValue;  // Значение, определяемое пользователем при создании объекта. Предназначено для идентификации отдельных экземпляров объекта.  
   
   
   void SetMyObjectType(EMyObjectTypes motType) { m_motType = motType; };  

   // Функции вывода на печать параметров. 
   void _PrintStringParameter(string strParameterName,string strParameterValue) { Print("Object ID: " + IntegerToString(GetType()) + "; " + strParameterName + " = " + strParameterValue + "; String."); };
   void _PrintDoubleParameter(string strParameterName,double dParameterValue,int iDigits = 8) { Print("Object ID: " + IntegerToString(GetType()) + "; " + strParameterName + " = " + DoubleToString(dParameterValue,iDigits) + "; Double"); };
   void _PrintIntegerParameter(string strParameterName,long lParameterValue) {  Print("Object ID: " + IntegerToString(GetType()) + "; " + strParameterName + " = " + IntegerToString(lParameterValue) + "; Integer"); };
   void _PrintBoolParameter(string strParameterName,bool bParameterValue) { if(bParameterValue) Print("Object ID: " + IntegerToString(GetType()) + "; " + strParameterName + " = True; Bool"); else Print("Object ID: " + IntegerToString(GetType()) + "; " + strParameterName + " = False; Bool"); };
   
public:
   CMyObject(int iUDCreationValue = WRONG_VALUE) { m_iUDCreationValue = iUDCreationValue;  m_motType = MOT_UNKNOWN;  };
   
   EMyObjectTypes GetType() const { return(m_motType);    };
   bool CheckType(EMyObjectTypes motType) { return(m_motType == motType); }; 
   
   int GetUDCreationValue() { return(m_iUDCreationValue); };
   void SetUDCreationValue(int iValue) { m_iUDCreationValue = iValue; };
};

#ifdef  ASSERTION_CODE_ON

CMyObject* _PerformObjectConvertWithCheck(CMyObject* pmoObject,EMyObjectTypes motType)
{
   ASSERT_MYPOINTER(pmoObject);                    // проверим указатель
   ASSERT(pmoObject.CheckType(motType) == true);   // проверим внутренний ID типа объекта
   
   return(pmoObject);
};

#define  CONVERT_OBJECT_WITH_CHECK(objFrom,typeTo,checkType) ((typeTo*)_PerformObjectConvertWithCheck(objFrom,checkType))

#else // ASSERTION_CODE_ON

#define  CONVERT_OBJECT_WITH_CHECK(objFrom,typeTo,checkType) ((typeTo*)objFrom)

#endif // ASSERTION_CODE_ON

La macro CONVERT_OBJECT_WITH_CHECK è anche definita alla fine, che per la versione DEBUG esegue un ulteriore controllo di conversione del puntatore basato sul tipo di oggetto

 
George Merts:

Sostenere la cosa.

Ecco la mia classe CMyObject:

La macro CONVERT_OBJECT_WITH_CHECK è anche definita alla fine, che, per la versione DEBUG, esegue un ulteriore controllo di conversione del puntatore basato sul tipo di oggetto


È bellissimo. Naturalmente, è una questione di gusti. Ma, basandomi sulla sintassi MQL, lo scriverei così:

enum ENUM_OBJECT_TYPES
{
   OBJECT_TYPES_BASE_OBJECT                              =  0001,          // Просто CObject - фактически, никогда не должен использоваться.
   OBJECT_TYPES_STRUCT_WRAPPER                           =  0002,          // Неинициализированный CStructWrapper
   OBJECT_TYPES_PRICE_POINT                              =  0003,          // Класс CPricePoint   
   OBJECT_TYPES_PRICEIDX_POINT                           =  0004,          // Класс CPriceIdxPoint  
   OBJECT_TYPES_WPRICEIDX_POINT                          =  0005,          // Класс CWPriceIdxPoint  
   OBJECT_TYPES_WAVE_TRIANGLE_DATA                       =  0006,          // Класс CWaveTriangleData
   OBJECT_TYPES_WAVE_TRIANGLE                            =  0007,          // Класс CWaveTriangle
   OBJECT_TYPES_TRADERESULT_I                            =  0008,          // Класс CTradeResultI
   OBJECT_TYPES_TRADERESULT                              =  0009,          // Класс CTradeResult

   // Тут еще куча типов объектов - для каждого класса, свой ID
           
   OBJECT_TYPES_UNKNOWN                                  = -0001           // Неинициализированный объект.
};
 
Dennis Kirichenko:

È bellissimo. Naturalmente, è una questione di gusti. Ma, basandomi sulla sintassi MQL, lo scriverei in questo modo:

Sì, proprio così.

Ma questo è il mio "stile di programmazione" senile (ciao, Volchansky con il suo recente thread).

Ho tutte le enumerazioni - iniziano con E, e poi con la notazione "gobba" - nome. E i tipi stessi in enumerazione iniziano con un'abbreviazione (fino a quattro lettere) di tipo enumerazione.

Di conseguenza, poiché l'enumerazione è EMyObjectType, tutti i valori iniziano con MOT_

 
Комбинатор:

Sei un idiota? )) Non ho detto una parola negativa su F#. Impara a leggere e a capire quello che ti viene detto prima di postare i tuoi stupidi commenti.

Se si confronta OOP con FP, è più sensato confrontarlo con un linguaggio FP puro, cioè Haskel. F# è già così così, mentre Python e R non lo sono affatto. Questo è quello che voglio dire. Altrimenti potremmo arrivare ad un punto in cui il C++ è anche un linguaggio FP.

Sei un troll analfabeta. Per la cronaca, tutte le lingue elencate sono funzionali in un modo o nell'altro. Andate a imparare la materia. La domanda è stata posta per capire in quale quadro di riferimentoAndrei sta probabilmente praticando uno dei linguaggi della FP, quindi l'elenco era molto generale.

 
George Merts:

Cosa dovrebbe significare?

Cosa dovrebbe esserci nell'"oggetto base" secondo voi?

Personalmente ho quasi TUTTI gli oggetti in tutti i miei progetti - ereditati da CMyObject: public CObject, (nel mio oggetto sono aggiunti altri due campi - nome della classe e ID dell'istanza), e ripetutamente ho trovato che ho bisogno della funzionalità CObject::Compare() molto. Un paio di volte sono stati utili anche i puntatori di liste.

CObject ha un solo obiettivo: fornire il controllo dei tipi. E ci riesce traballantemente. Metodi come Next(), Prev(), ecc. sono per collezioni molto specializzate. Non appartengono a CObject. Lo stesso vale per i metodi Save e Load. Sarebbe bello non avere nemmeno Comparer, ma questa è l'unica soluzione senza interfacce.

Per quanto riguarda il metodo Type(), non fornisce una tipizzazione rigorosa, perché restituisce il solito numero. Potete vedere sull'esempio del vostro codice. Si definisce un nuovo metodo GetType() che restituisce il tipo come enumerazione. Non c'è davvero altro modo, lo faccio da solo. Per questo si deve aggiungere il CObject standard, ed è scorretto.

 

Continuiamo con CObject::Compare().

Ho tale oggetto CFactoryBalanceResultSeries - è una serie con risultati di bilanciamento con riferimento all'oggetto factory di Expert Advisor. In realtà è una curva di equilibrio sulla storia con riferimento all'Expert Advisor che l'ha scambiata.

Quindi ho uno script in cui confronto queste serie molto equilibrate.

Finché ci sono solo due serie è facile confrontarle. Ma quando ce ne sono dozzine - non si può confrontare a occhio, è necessario un confronto più formale.

E solo per automatizzare questo processo - ho dovuto scrivere una funzione che ordina proprio queste serie. E qui è stato utile, perché la classe CFactoryBalanceResultSeries è un erede di CObject con la sua funzione di confronto. Se sovrascriviamo questa funzione, abbiamo una pronta possibilità di ordinare le serie.

Ecco come appare questa funzione nel mio caso:

int CFactoryBalanceResultSeries::Compare(const CObject *poNode,const int iMode) const
{
   CFactoryBalanceResultSeries* pfdsAnother = CONVERT_OBJECT_WITH_CHECK(poNode,CFactoryBalanceResultSeries,MOT_FACTORYBALANCERES_SERIES);
   
   switch(iMode)
      {
      case FSM_BY_PART_OF_MAX_DD_A:    return(_CompareByPartOfMaxDDWith(pfdsAnother,true));
      case FSM_BY_PART_OF_MAX_DD_D:    return(_CompareByPartOfMaxDDWith(pfdsAnother,false));

      case FSM_BY_PART_OF_MAX_SLQUEUE_A: return(_CompareByPartOfMaxSLQueueWith(pfdsAnother,true));
      case FSM_BY_PART_OF_MAX_SLQUEUE_D: return(_CompareByPartOfMaxSLQueueWith(pfdsAnother,false));

      case FSM_BY_LAST_PRCDATA_A:      return(_CompareByLastPrcdataWith(pfdsAnother,true));
      case FSM_BY_LAST_PRCDATA_D:      return(_CompareByLastPrcdataWith(pfdsAnother,false));
      case FSM_BY_LAST_MNYDATA_A:      return(_CompareByLastMnydataWith(pfdsAnother,true));
      case FSM_BY_LAST_MNYDATA_D:      return(_CompareByLastMnydataWith(pfdsAnother,false));
      case FSM_BY_LAST_MNYLOTDATA_A:   return(_CompareByLastMnylotdataWith(pfdsAnother,true));
      case FSM_BY_LAST_MNYLOTDATA_D:   return(_CompareByLastMnylotdataWith(pfdsAnother,false));
      
      case FSM_BY_PRCYEARRECOVERY_A:   return(_CompareByYearPrcrecoveryWith(pfdsAnother,true));
      case FSM_BY_PRCYEARRECOVERY_D:   return(_CompareByYearPrcrecoveryWith(pfdsAnother,false));
      case FSM_BY_MNYYEARRECOVERY_A:   return(_CompareByMnyYearRecoveryWith(pfdsAnother,true));
      case FSM_BY_MNYYEARRECOVERY_D:   return(_CompareByMnyYearRecoveryWith(pfdsAnother,false));
      case FSM_BY_MNYLOTYEARRECOVERY_A:return(_CompareByMnylotYearRecoveryWith(pfdsAnother,true));
      case FSM_BY_MNYLOTYEARRECOVERY_D:return(_CompareByMnylotYearRecoveryWith(pfdsAnother,false));
      
      case FSM_BY_PRCVAR_A:            return(_CompareByPrcVarWith(pfdsAnother,true));
      case FSM_BY_PRCVAR_D:            return(_CompareByPrcVarWith(pfdsAnother,false));
      case FSM_BY_MNYVAR_A:            return(_CompareByMnyVarWith(pfdsAnother,true));
      case FSM_BY_MNYVAR_D:            return(_CompareByMnyVarWith(pfdsAnother,false));
      case FSM_BY_MNYLOTVAR_A:         return(_CompareByMnylotVarWith(pfdsAnother,true));
      case FSM_BY_MNYLOTVAR_D:         return(_CompareByMnylotVarWith(pfdsAnother,false));
      
      case FSM_BY_PRC_GRAILRATIO_A:    return(_CompareByPrcGrailratioWith(pfdsAnother,true));
      case FSM_BY_PRC_GRAILRATIO_D:    return(_CompareByPrcGrailratioWith(pfdsAnother,false));

      case FSM_BY_MAGIC_A:             return(_CompareByMagicWith(pfdsAnother,true));
      case FSM_BY_MAIGC_D:             return(_CompareByMagicWith(pfdsAnother,false));
      default:
         break;
      };
         
   return(NULL);
};

Cioè, a seconda del tipo di ordinamento - selezioniamo la funzione di confronto richiesta, che viene utilizzata nella funzione di ordinamento generale.

Per esempio, se vogliamo ordinare la serie dei saldi in base alla parte dell'ultimo prelievo dal massimo, si useranno le seguenti funzioni:

int CFactoryBalanceResultSeries::_CompareDblData(double dDataFirst,double dDataSecond,bool bAccending) const
{
   if(dDataFirst > dDataSecond)
      {
      if(bAccending)
         return(1);
      else   
         return(-1);
      };
   
   if(dDataFirst < dDataSecond)
      {
      if(bAccending)
         return(-1);
      else   
         return(1);
      };
      
   return(NULL);         
};

int CFactoryBalanceResultSeries::_CompareByPartOfMaxDDWith(CFactoryBalanceResultSeries* pfdsAnother,bool bAccending) const
{
   if(Total()==0 || pfdsAnother.Total() == 0 || m_pepfFactory.GetControlParams().m_dMaxPriceDrawdown == 0)
      return(NULL);
   
   double dLocalPart = GetCurPriceDD() / m_pepfFactory.GetControlParams().m_dMaxPriceDrawdown;
   double dRemotePart = pfdsAnother.GetCurPriceDD() / pfdsAnother.GetFactory().GetControlParams().m_dMaxPriceDrawdown;
      
   return(_CompareDblData(dLocalPart,dRemotePart,bAccending));   
};
 
George Merts:

Continuerò con CObject::Compare().

Dal recente

CDouble & CDoubleVector
CDouble & CDoubleVector
  • voti: 4
  • 2018.01.09
  • nicholishen
  • www.mql5.com
A library for common rounding methods used in MQL development, primitive wrapper class for type (double), and vector for CDouble objects. MQL5 and MQL4 compatible! CDouble The CDouble class wraps a value of the primitive type double in an object. Additionally, this class provides several methods and static methods for rounding doubles and...
 
George Merts:



Non è molto bello, imho.

int CFactoryBalanceResultSeries::Compare(const CObject *poNode,const int iMode) const
{
   CFactoryBalanceResultSeries* pfdsAnother = CONVERT_OBJECT_WITH_CHECK(poNode,CFactoryBalanceResultSeries,MOT_FACTORYBALANCERES_SERIES);
   
   switch(iMode)
      {
      case FSM_BY_PART_OF_MAX_DD_A:    return(_CompareByPartOfMaxDDWith(pfdsAnother,true));
      case FSM_BY_PART_OF_MAX_DD_D:    return(_CompareByPartOfMaxDDWith(pfdsAnother,false));

      case FSM_BY_PART_OF_MAX_SLQUEUE_A: return(_CompareByPartOfMaxSLQueueWith(pfdsAnother,true));
      case FSM_BY_PART_OF_MAX_SLQUEUE_D: return(_CompareByPartOfMaxSLQueueWith(pfdsAnother,false));

Si potrebbe usare un puntatore a una funzione.

typedef int (*TCompare1)(int,bool); 
// ---
int CFactoryBalanceResultSeries::Compare(const CObject *poNode,const int iMode) const
{
   CFactoryBalanceResultSeries* pfdsAnother = CONVERT_OBJECT_WITH_CHECK(poNode,CFactoryBalanceResultSeries,MOT_FACTORYBALANCERES_SERIES);
   
   switch(iMode)
      {
      case FSM_BY_PART_OF_MAX_DD_A:    return(TCompare1(pfdsAnother,true));
      case FSM_BY_PART_OF_MAX_DD_D:    return(TCompare1(pfdsAnother,false));

      case FSM_BY_PART_OF_MAX_SLQUEUE_A: return(TCompare1(pfdsAnother,true));
      case FSM_BY_PART_OF_MAX_SLQUEUE_D: return(TCompare1(pfdsAnother,false));

.....
      }
}
 
George Merts:

Sì, proprio così.

Ma, questo è il mio 'stile di programmazione' senile (ciao, Wolchansky con il suo recente thread).

Con me, tutte le enumerazioni - iniziano con E, e poi con la notazione "gobba" - nome. E i tipi stessi in enumerazione iniziano con un'abbreviazione (fino a quattro lettere) di tipo enumerazione.

Corrispondentemente, poiché l'enumerazione EMyObjectType - tutti i valori iniziano con MOT_


Sì, ho la stessa enumerazione.

ZS: Sono arrivato ora al computer. Come previsto, questo thread è rapidamente sceso nella spazzatura). Cercherò di finire la storia delle funzioni virtuali più tardi. Dovremmo chiamare questo forum Blah Blah Blah Blah).

 

Ho letto i diversi interessi di ognuno... Sono in procinto di ridisegnare una classe per impostare e gestire una griglia virtuale, ne ho bisogno.