ООП, шаблоны и макросы в mql5, тонкости и приёмы использования - страница 10

 
Alexey Navoykov:

Да и это всё-равно бессмысленно в общем случае.  Ведь цепочка наследования могла быть какая угодно:  хоть  Interface<CBase>,  хоть Interface<C<B<A<CBase>>>>, вариантов немерено.  Придётся CBase кастить последовательно ко всем возможным вариантам, что нереально.

Я помню собирался реализовать хранение информации об интерфейсах в самом объекте класса.  И в дополнение к существующим интерфейсным прокладкам сделать самостоятельные интерфейсные классы, которые бы работали как обёртка над нашей прокладкой.   Да только потом пришёл к выводу, что это всё лишнее и не нужное.   Практической потребности кастить базовый класс к какому либо интерфейсу я не встречал.  Это просто как-то нелогично.  Единственный вариант - в отладочных целях узнать, поддерживает ли класс данный интерфейс, но для этого кастинг как таковой не нужен.

На мой взгляд, хранить интерфейс нужно в самом интерфейсе. Interface<T,CBase>::GetComparer().Compare(CBase &a, T& b); Я там набросал код для примера, но что-то не очень хочется захламлять форум многобуквами.

 
Ilya Malev:

На мой взгляд, хранить интерфейс нужно в самом интерфейсе. Interface<T,CBase>::GetComparer().Compare(CBase &a, T& b); Я там набросал код для примера, но что-то не очень хочется захламлять форум многобуквами.

Выкладывайте. Это в любом случае не хлам, а предмет обсуждения. Вот в той ветке, из которой сюда перенесли обсуждение, вот там - да, было бы неуместно.

 

ок)

//+------------------------------------------------------------------+
//|                                                    Comparer demo |
//|                                      Copyright 2012, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#property strict

#define throw(M)   {int a=0,b=1; printf("%s: %s",__FUNCSIG__,M); Print(b%a); } 
#define msg_pure   "Method not implemented!"
#define msg_compare "Types are uncomparable!"


template<typename T,typename CBase>
class IComparer;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class Number
  {
public:
   virtual int CompareTo(Number *par)
    { 
      throw(msg_pure); return 0; 
    }
   int operator==(Number*par)
    {
      return CompareTo(par);
    }
   template<typename T> 
   T *operator[](T*)
    { 
      return dynamic_cast<T*>(&this); 
    }
   virtual string ToStr()
    { 
      return StringFormat("Type %s, object %i (%i)",typename(this),&this,CheckPointer(&this));
    }
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class Int: public Number
  {
private:
   int               i;
public:
   int Get()
    { 
      return i; 
    }
   Int*Set(int p)
    { 
      i=p; 
      return &this; 
    }
   virtual int CompareTo(Number*par)
     {
      Int*v1=dynamic_cast<Int*>(par);
      if(v1)
       {
        return IComparer<Int,Int>::GetComparer()[ IComparer<Int,Int>::GetComparer() ].Compare( &this,v1 );
       }
      
      Double*v2=dynamic_cast<Double*>(par);
      if(v2)
       {
        return IComparer<Double,Int>::GetComparer()[ IComparer<Double,Int>::GetComparer() ].Compare( &this,v2 );
       }
       
      throw(msg_compare); return 0;
     }
   Int*operator=( int p )
    { 
      return Set( p ); 
    }
   virtual string ToStr()
    { 
      return IntegerToString(i); 
    }
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class Double: public Number
  {
private:
   double            f;
public:
   double Get()
    { 
      return f; 
    }
   Double*Set(double p)
    { 
      f=p; 
      return &this; 
    }
   virtual int CompareTo(Number*par)
     {
      Double*v1=dynamic_cast<Double*>(par);
      if(v1)
       {
        return IComparer<Double,Double>::GetComparer()[ IComparer<Double,Double>::GetComparer() ].Compare( &this,v1 );
       }
       
      Int*v2=dynamic_cast<Int*>(par);
      if(v2)
       {
        return IComparer<Int,Double>::GetComparer()[ IComparer<Int,Double>::GetComparer() ].Compare( &this,v2 );
       }
       
      throw(msg_compare); return 0;
     }
   Double*operator=(double p)
    { 
      return Set(p); 
    }
   virtual string ToStr()
    { 
      return DoubleToString(f,_Digits); 
    }
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
template<typename T,typename CBase>
class IComparer: public CBase
  {
private:
   static IComparer *comparer;
public:
   IComparer()
    { 
      if(!comparer) 
       {
        comparer=&this; 
       }
    }
   virtual int Compare(CBase &op1,T &op2)
    { 
      throw(msg_pure); 
      return 0; 
    }

   static IComparer *GetComparer()
    { 
      return comparer ? comparer : new IComparer; 
    }
   static string ToStr(int cmp)
    { 
      return(!cmp?"equal":(cmp==-1?"lesser than":(cmp==1?"greater than":"undefined"))); 
    }
  };

template<typename T,typename CBase>
IComparer *IComparer::comparer=NULL;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CmpIntToInt: public IComparer<Int,Int>
  {
   virtual int Compare(Int &op1,Int &op2)
    { 
      return(op1.Get()>op2.Get())-(op1.Get()<op2.Get()); 
    }
  }
citi;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CmpIntToDouble: public IComparer<Int,Double>
  {
   virtual int Compare(Double &op1,Int &op2)
    { 
      return int(op1.Get()-op2.Get()>DBL_EPSILON)-int(op2.Get()-op1.Get()>DBL_EPSILON); 
    }
  }
citd;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CmpDoubleToInt: public IComparer<Double,Int>
  {
   virtual int Compare(Int &op1,Double &op2)
    { 
      return int(op1.Get()-op2.Get()>DBL_EPSILON)-int(op2.Get()-op1.Get()>DBL_EPSILON); 
    }
  }
cdti;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CmpDoubleToDouble: public IComparer<Double,Double>
  {
   virtual int Compare(Double &op1,Double &op2)
    { 
      return int(op1.Get()-op2.Get()>DBL_EPSILON)-int(op2.Get()-op1.Get()>DBL_EPSILON); 
    }
  }
cdtd;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   srand(GetTickCount());
   Number *n[10];

   for(int i=0;i<10;i++)
     {
      if(rand()%2==0) n[i]=new Int=rand();
      else            n[i]=new Double=rand()*rand()/(1.0*rand());
     }

   for(int i=0;i<10;i++)
     {
      int a=rand()%10,b=rand()%10;
      printf("%s is %s %s",n[a].ToStr(),IComparer<Int,Int>::ToStr(*n[a]==n[b]),n[b].ToStr());
     }

   for(int i=0;i<10;i++)
     {
      delete n[i];
     }
  }
//+------------------------------------------------------------------+
 
Ilya Malev:

ок)

 А почему там метод IComparer::Compare(CBase &op1, T &op2),  если оба аргумента должны быть T

 
Alexey Navoykov:

 А почему там метод IComparer::Compare(CBase &op1, T &op2),  если оба аргумента должны быть T

Разве сравнивать можно только одинаковые типы? Я исходил из того, что нет. Сделайте T==CBase и будут оба аргумента Т )

 

А, понял, тогда вас неправильно всё сделано.  Класс IComparer в вашем случае должен быть как IComparer<T1,T2,CBase>.  Соответственно и метод будет: 

virtual Compare(T1 &op1, T2 &op2) = 0;

И при наследовании класса вы будете перегружать именно этот метод, всё станет на свои места.
 
Alexey Navoykov:

А, понял, тогда вас неправильно всё сделано.  Класс IComparer в вашем случае должен быть как IComparer<T1,T2,CBase>.  Соответственно и метод будет: 

И при наследовании класса вы будете перегружать именно этот метод, всё станет на свои места.

А смысл в этом CBase? И почему должны сравниваться именно 2 значения одного типа?

 
У меня нет цели сделать точно как в С#, к тому же я детально не разбирался как там все сделано. Но навскидку тот же IEnumerator из двух функций reset и next крайне малоудобен, его копировать в том же виде я бы точно не стал )
 

dynamic cast для сравнения?? вы в своем уме?

чисто виртуальная функция пишется так - virtual int CompareTo(Number *par) = 0;

будет ругаться компилятор а не самописный суррогат исключений.

 
TheXpert:

чисто виртуальная функция пишется так - virtual int CompareTo(Number *par) = 0;

будет ругаться компилятор а не самописный суррогат исключений.

Мне как раз не нужно, чтобы ругался компилятор, потому что постоянно манипулирую классами базового типа (в этом примере Number). Если компилятор будет на него ругаться, то код не выполнится вообще