OOP, templates and macros in mql5, subtleties and uses - page 10

 
Alexey Navoykov:

After all, the inheritance chain could be anything you want: even Interface<CBase>, even Interface<C<B<A<CBase>>>>, there are tons of variants. We would have to cast CBase sequentially to all possible variants, which is unrealistic.

I remember I was going to implement storing information about interfaces in class object itself, and in addition to existing interface pads to make independent interface classes that would work as a wrapper over our pad. But then I came to the conclusion that all this is unnecessary and redundant. In practice, I've never seen a need to cast a base class to any interface, it just doesn't make any sense. The only option is to find out if the class supports this interface for debugging purposes, but we don't need casting for that.

In my opinion, we should store the interface in the interface. Interface<T,CBase>::GetComparer().Compare(CBase &a, T& b); I sketched some code there for an example, but I don't really want to clutter up the forum with too many letters.

 
Ilya Malev:

In my opinion, the interface should be stored in the interface itself. Interface<T,CBase>::GetComparer().Compare(CBase &a, T& b); I sketched some code there for an example, but I don't really want to clutter up the forum with too many letters.

Go ahead and post it. Anyway, it's not rubbish but a subject of discussion. But in that thread from which the discussion was moved here, it would be inappropriate.

 

ok)

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

ok)

Why isIComparer::Compare(CBase &op1, T &op2) method there if both arguments should be T

 
Alexey Navoykov:

And why thereIComparer::Compare(CBase &op1, T &op2) method if both arguments must be T

Is it only possible to compare the same types? My assumption is that it's not. Make T==CBase and there will be both arguments T )

 

Ah, got it, you've got it wrong then. IComparer class in your case should be like IComparer<T1,T2,CBase>. Accordingly the method will be:

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

And when you inherit the class you will overload exactly this method, everything will fall into place.
 
Alexey Navoykov:

Ah, I see, you've got it all wrong then. IComparer class in your case should be like IComparer<T1,T2,CBase>:

And when you inherit a class, you will overload this method, everything will fall into place.

And what's the meaning of this CBase? And why exactly 2 values of one type must be compared?

 
I don't have a goal to make it exactly like in C#, moreover, I haven't understood in detail how it's done there. But at a glance the IEnumerator of two functions reset and next is very inconvenient, I definitely would not copy it in the same form )
 

dynamic cast for comparison? are you out of your mind?

a pure virtual function is written like this -virtual int CompareTo(Number *par) = 0 ;

it is the compiler that will be cursed and not the self-written exception surrogate.

 
TheXpert:

a pure virtual function is written like this -virtual int CompareTo(Number *par) = 0;

the compiler will be cursed instead of the self-written exception surrogate.

I don't need the compiler to swear because I constantly manipulate base type classes (Number in this example). If the compiler swears at it, the code won't run at all