Разговоры на завалинке о ООП - страница 4

 
Dennis Kirichenko:

Дельное замечание. Было бы здОрово, если бы аргументы подкреплялись кодом, а не просто так, бла-бла-бла.

Подкрепляю.

Вот мой класс 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

В конце также определяется макрос CONVERT_OBJECT_WITH_CHECK, который для DEBUG-версии осуществляет дополнительную проверку преобразования указателей, исходя из типа объекта

 
George Merts:

Подкрепляю.

Вот мой класс CMyObject:

В конце также определяется макрос CONVERT_OBJECT_WITH_CHECK, который для DEBUG-версии осуществляет дополнительную проверку преобразования указателей, исходя из типа объекта


Красиво. Конечно дело вкуса. Но, исходя из MQL-синтаксиса, написал бы так:

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:

Красиво. Конечно дело вкуса. Но, исходя из MQL-синтаксиса, написал бы так:

Да, верно.

Но, это мой старперский "стиль программирования" (привет, Волчанский с его недавней веткой).

У меня все перечисления - начинаются с E, и потом "горбатой" нотацией - название. А сами типы в перечислении - начинаются с сокращения (до четырех букв) типа перечисления.

Соответственно, раз перечисление EMyObjectType - то все значения начинаются с MOT_

 
Комбинатор:

Ты идиот? )) я не сказал ни одного плохого слова про F#. Научись читать и понимать что тебе пишут перед тем как постить свои тупые каменты

Если сравнивать ООП с ФП, то сравнивать имеет смысл с чистым ФП языком, т.е. хаскелем. F# уже так себе, а питон и R совсем нет. Вот что я имел в виду. А то так можно договориться до того что С++ тоже к ФП относится.

Троль ты безграмотный. Для справки все перечисленные языки в той или иной мере функциональные. Иди и поучи предметную область. Вопрос задавался что бы понять в какой системе координат находится Andrei Возможно он практикует один из языков ФП, поэтому и перечисление было очень общим.

 
George Merts:

Абаснуй ?

Что должно быть по твоему в "базовом объекте" ?

Лично у меня почти ВСЕ объекты во всех проектах - наследуются от класса CMyObject: public CObject, (в моем объекте добавляются еще два поля - название класса и ID экземпляра), и неоднократно убеждался в том, что мне функциональность CObject::Compare() - оказывалась весьма и весьма нужной. Пару раз пригодились и указатели списка.

У CObject одна задача - обеспечить контроль типов. И с этим он шатко-валко справляется. Методы вроде Next(), Prev() и т.д. это для очень специализированных коллекций. Им не место в CObject. Тоже касается методов Save и Load. По-хорошему и Comparer'а в нем не должно быть, но без интерфейсов это единственное решение.

Что касается метода Type() то он не обеспечивает строгую типизацию т.к. возвращает обычное число. Можно убедится на примере твоих собственных кодов. Ты определяешь новый метод GetType(), который возвращает тип в виде перечисления. И действительно по другому никак, сам так делаю. Поэтому выходит стандартный CObject приходится дописывать, а это неправильно. 

 

Продолжу по поводу CObject::Compare().

Есть у меня такой объект CFactoryBalanceResultSeries - это серия с результатами баланса со ссылкой на объект-фабрику эксперта. Фактически, это кривая баланса на истории, со ссылкой на эксперт, который ее торговал.

Так вот, у меня есть скрипт, на котором я сравниваю эти самые серии баланса.

Пока серий только две - их сравнить легко. А вот когда их десяток - уже на глаз - хрен сравнишь, надо более формальное сравнение.

И, как раз для автоматизации этого процесса - надо было написать функцию, сортирующую эти самые серии. Тут как раз мне и пригодилось то, что класс CFactoryBalanceResultSeries  - это наследник от CObject, c его функцией сравнения. Переопределяем эту функцию - и имеем готовую возможность сортировки серий.

У меня эта функция выглядит так:

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

То есть, в зависимости от типа сортировки - мы выбираем нужную функцию сравнения, которая и используется в общей функции сортировки.

Для примера, если мы хотим отсортировать серии баланса по части последнего просада от максимума, то будут использовать следующие функции:

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:

Продолжу по поводу CObject::Compare().

Из свежего

CDouble & CDoubleVector
CDouble & CDoubleVector
  • голосов: 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:



Имхо, не очень красиво.

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

Можно использовать указатель на функцию.

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:

Да, верно.

Но, это мой старперский "стиль программирования" (привет, Волчанский с его недавней веткой).

У меня все перечисления - начинаются с E, и потом "горбатой" нотацией - название. А сами типы в перечислении - начинаются с сокращения (до четырех букв) типа перечисления.

Соответственно, раз перечисление EMyObjectType - то все значения начинаются с MOT_


Да, у меня так же перечисления.

ЗЫ: Только сейчас добрался до компа. Как и ожидалось, ветка быстренько скатилась во флуд )) Попробую попозже завершить рассказ про виртуальные функции.. Надо назвать этот форум так : чат-форум Бла-Бла-Бла )) 

 

Прочитал все, какие у всех разные интересы...Я вот сейчас переделываю класс для выставления и управления виртуальной сеткой, мне это надо.