Parler de l'OLP dans le salon - page 4

 
Dennis Kirichenko:

Bon point. Ce serait bien si les arguments étaient étayés par du code plutôt que de se contenter de bla, bla, bla.

C'est ce que je fais.

Voici ma 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 est également définie à la fin, qui, pour la version DEBUG, effectue un contrôle supplémentaire de la conversion des pointeurs en fonction du type d'objet.

 
George Merts:

C'est ce que je fais.

Voici ma classe CMyObject :

La macro CONVERT_OBJECT_WITH_CHECK est également définie à la fin, qui, pour la version DEBUG, effectue un contrôle supplémentaire de la conversion des pointeurs en fonction du type d'objet


C'est magnifique. Bien sûr, c'est une question de goût. Mais, en me basant sur la syntaxe MQL, je l'écrirais comme ceci :

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:

C'est magnifique. Bien sûr, c'est une question de goût. Mais, en me basant sur la syntaxe MQL, je l'écrirais de cette façon :

Oui, c'est vrai.

Mais, c'est mon "style de programmation" sénile (bonjour, Volchansky avec son récent fil de discussion).

J'ai toutes les énumérations - commencent par E, puis avec la notation "bosse" - nom. Et les types eux-mêmes dans l'énumération commencent par une abréviation (jusqu'à quatre lettres) de type énumération.

Par conséquent, puisque l'énumération est EMyObjectType, toutes les valeurs commencent par MOT_.

 
Комбинатор:

Vous êtes un idiot ? )) Je n'ai pas dit un seul mot négatif sur F#. Apprenez à lire et à comprendre ce qu'on vous dit avant de poster vos commentaires stupides.

Si vous comparez la POO à la FP, il est plus judicieux de la comparer à un langage FP pur, c'est-à-dire Haskel. F# n'est déjà pas terrible, alors que python et R ne le sont pas du tout. C'est ce que je veux dire. Sinon, nous risquons d'en arriver à ce que le C++ soit également un langage FP.

Vous êtes un troll analphabète. Pour mémoire, toutes les langues citées sont fonctionnelles d'une manière ou d'une autre. Allez-y et apprenez le sujet. La question était posée pour comprendre dans quel cadre de référenceAndrei pratique probablement l'une des langues de la FP, la liste était donc très générale.

 
George Merts:

Qu'est-ce que ça veut dire ?

Que devrait contenir l'"objet de base" selon vous ?

Personnellement, j'ai presque TOUS les objets dans tous mes projets - hérités de CMyObject : public CObject, (dans mon objet, deux champs supplémentaires sont ajoutés - le nom de la classe et l'ID de l'instance), et j'ai constaté à plusieurs reprises que j'ai beaucoup besoin de la fonctionnalité CObject::Compare(). Quelques fois, les pointeurs de liste ont également été utiles.

CObject n'a qu'un seul objectif : fournir un contrôle des types. Et il y parvient de manière chancelante. Les méthodes comme Next(), Prev(), etc. sont destinées à des collections très spécialisées. Ils n'ont pas leur place dans CObject. Il en va de même pour les méthodes de sauvegarde et de chargement. Ce serait bien de ne pas y inclure Comparer non plus, mais c'est la seule solution sans interfaces.

Quant à la méthode Type(), elle ne permet pas un typage strict, car elle renvoie le nombre habituel. Vous pouvez voir sur l'exemple de votre propre code. Vous définissez une nouvelle méthode GetType() qui renvoie le type sous forme d'énumération. Il n'y a vraiment pas d'autre moyen, je le fais moi-même. C'est pourquoi la norme CObject doit y être annexée, ce qui est incorrect.

 

Poursuivons avec CObject::Compare().

J'ai un tel objet CFactoryBalanceResultSeries - c'est une série avec les résultats de la balance en référence à l'objet factory de l'Expert Advisor. En fait, il s'agit d'une courbe d'équilibre sur l'historique par rapport au conseiller expert qui l'a négocié.

Donc, j'ai un script où je compare ces séries très équilibrées.

Tant qu'il n'y a que deux séries, il est facile de les comparer. Mais lorsqu'il y en a des dizaines, vous ne pouvez pas comparer à l'œil, vous avez besoin d'une comparaison plus formelle.

Et juste pour l'automatisation de ce processus - j'ai dû écrire une fonction qui trie ces mêmes séries. Et là, c'était utile, car la classe CFactoryBalanceResultSeries est une héritière de CObject avec sa fonction de comparaison. Si nous remplaçons cette fonction, nous avons la possibilité de trier les séries.

Voici à quoi ressemble cette fonction dans mon cas :

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);
};

C'est-à-dire que, selon le type de tri, nous sélectionnons la fonction de comparaison requise, qui est utilisée dans la fonction de tri générale.

Par exemple, si nous voulons trier la série de soldes par la partie du dernier drawdown par rapport au maximum, les fonctions suivantes seront utilisées :

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:

Je vais continuer avec CObject::Compare().

D'après le récent

CDouble & CDoubleVector
CDouble & CDoubleVector
  • votes : 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:



Ce n'est pas très joli, 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));

Vous pouvez utiliser un pointeur vers une fonction.

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:

Oui, c'est vrai.

Mais, c'est mon "style de programmation" sénile (bonjour, Wolchansky avec son récent fil de discussion).

Avec moi, toutes les énumérations - commencent par E, et ensuite avec la notation "bosse" - nom. Et les types eux-mêmes dans l'énumération commencent par une abréviation (jusqu'à quatre lettres) de type énumération.

De même, puisque l'énumération EMyObjectType - toutes les valeurs commencent par MOT_.


Oui, j'ai la même énumération.

ZS : Je viens juste d'arriver à l'ordinateur. Comme prévu, ce fil de discussion a rapidement sombré dans le n'importe quoi). J'essaierai de terminer l'histoire des fonctions virtuelles plus tard. Nous devrions appeler ce forum Blah Blah Blah Blah).

 

J'ai lu les différents intérêts de chacun... Je suis en train de refaire une classe pour mettre en place et gérer une grille virtuelle, j'en ai besoin.

Raison: