OOP, modelli e macro in mql5, sottigliezze e usi - pagina 10

 
Alexey Navoykov:

Dopo tutto, la catena di eredità potrebbe essere qualsiasi cosa: anche Interface<CBase>, anche Interface<C<B<A<CBase>>>>, ci sono tonnellate di varianti. Dovremmo lanciare CBase in modo sequenziale a tutte le possibili varianti, il che non è realistico.

Ricordo che avevo intenzione di implementare la memorizzazione delle informazioni sulle interfacce nell'oggetto classe stesso, e in aggiunta ai pad di interfaccia esistenti per fare classi di interfaccia indipendenti che avrebbero funzionato come un wrapper sopra il nostro pad. Ma poi sono arrivato alla conclusione che tutto questo era inutile e superfluo. In pratica, non ho mai visto la necessità di lanciare una classe base a qualsiasi interfaccia, semplicemente non ha alcun senso. L'unica opzione è scoprire se la classe supporta questa interfaccia per scopi di debug, ma non abbiamo bisogno del casting per questo.

Secondo me, dovremmo memorizzare l'interfaccia nell'interfaccia. Interface<T,CBase>::GetComparer().Compare(CBase &a, T& b); Ho abbozzato del codice per un esempio, ma non voglio davvero ingombrare il forum con troppe lettere.

 
Ilya Malev:

Secondo me, l'interfaccia dovrebbe essere memorizzata nell'interfaccia stessa. Interface<T,CBase>::GetComparer().Compare(CBase &a, T& b); Ho abbozzato del codice per un esempio, ma non voglio davvero ingombrare il forum con troppe lettere.

Vai avanti e pubblicalo. Comunque, non è spazzatura ma un argomento di discussione. Ma in quel thread da cui la discussione è stata spostata qui, sarebbe inappropriato.

 

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)

Perché il metodoIComparer::Compare(CBase &op1, T &op2) esiste se entrambi gli argomenti dovrebbero essere T

 
Alexey Navoykov:

E perché esiste il metodoIComparer::Compare(CBase &op1, T &op2) se entrambi gli argomenti devono essere T

È possibile confrontare solo gli stessi tipi? La mia ipotesi è che non lo sia. Fai T==CBase e ci saranno entrambi gli argomenti T )

 

Ah, ho capito, allora hai sbagliato tutto. La classe IComparer nel tuo caso dovrebbe essere come IComparer<T1,T2,CBase>. Di conseguenza, anche il metodo:

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

E quando si eredita la classe si sovraccarica esattamente questo metodo, tutto cadrà al suo posto.
 
Alexey Navoykov:

Ah, capisco, hai sbagliato tutto allora. La classe IComparer nel tuo caso dovrebbe essere come IComparer<T1,T2,CBase>:

E quando si eredita una classe, si sovraccarica questo metodo, tutto andrà a posto.

E cosa significa questo CBase? E perché si devono confrontare esattamente 2 valori di un tipo?

 
Non ho l'obiettivo di renderlo esattamente come in C#, inoltre, non ho capito in dettaglio come si fa lì. Ma a colpo d'occhio l'IEnumerator di due funzioni reset e next è molto scomodo, sicuramente non lo copierei nella stessa forma )
 

cast dinamico per il confronto? Sei fuori di testa?

una funzione virtuale pura è scritta così -virtuale int CompareTo(Number *par) = 0 ;

è il compilatore che sarà maledetto e non il surrogato di eccezione scritto in proprio.

 
TheXpert:

una funzione virtuale pura è scritta così -virtuale int CompareTo(Number *par) = 0;

il compilatore sarà maledetto al posto del surrogato di eccezione auto-scritto.

Non ho bisogno che il compilatore imprechi perché manipolo costantemente classi di tipo base (Numero in questo esempio). Se il compilatore impreca, il codice non funzionerà affatto

Motivazione: