OOP, templates et macros dans mql5, subtilités et utilisations - page 10

 
Alexey Navoykov:

Après tout, la chaîne d'héritage pourrait être tout ce que vous voulez : même Interface<CBase>, même Interface<C<B<A<CBase>>>>, il y a des tonnes de variantes. Nous devrions couler CBase séquentiellement vers toutes les variantes possibles, ce qui est irréaliste.

Je me souviens que j'allais implémenter le stockage d'informations sur les interfaces dans la classe objet elle-même, et en plus des tampons d'interface existants, créer des classes d'interface indépendantes qui fonctionneraient comme une enveloppe sur notre tampon. Mais j'en suis venu à la conclusion que tout cela était inutile et superflu. En pratique, je n'ai jamais vu le besoin de caster une classe de base vers une interface, cela n'a tout simplement aucun sens. La seule option est de savoir si la classe supporte cette interface à des fins de débogage, mais nous n'avons pas besoin de caster pour cela.

À mon avis, nous devrions stocker l'interface dans l'interface. Interface<T,CBase>::GetComparer().Compare(CBase &a, T& b) ; J'ai esquissé un peu de code ici pour un exemple, mais je ne veux pas vraiment encombrer le forum avec trop de lettres.

 
Ilya Malev:

À mon avis, l'interface devrait être stockée dans l'interface elle-même. Interface<T,CBase>::GetComparer().Compare(CBase &a, T& b) ; J'ai esquissé un peu de code ici pour un exemple, mais je ne veux pas vraiment encombrer le forum avec trop de lettres.

Allez-y et postez-le. Quoi qu'il en soit, ce ne sont pas des bêtises mais un sujet de discussion. Mais dans le fil de discussion dont la discussion a été déplacée ici, ce serait inapproprié.

 

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)

Pourquoi la méthodeIComparer::Compare(CBase &op1, T &op2) existe-t-elle si les deux arguments devraient être des T

 
Alexey Navoykov:

Et pourquoi il y a la méthodeIComparer::Compare(CBase &op1, T &op2) si les deux arguments doivent être des T

Est-il possible de comparer uniquement les mêmes types ? Je suppose qu'il ne l'est pas. Faites T==CBase et il y aura les deux arguments T )

 

Ah, j'ai compris, alors vous avez tout faux. La classe IComparer dans votre cas devrait être comme IComparer<T1,T2,CBase>. En conséquence, la méthode le sera aussi :

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

Et lorsque vous héritez de la classe, vous surchargerez exactement cette méthode, tout se mettra en place.
 
Alexey Navoykov:

Ah, je vois, vous avez tout faux alors. La classe IComparer dans votre cas devrait être comme IComparer<T1,T2,CBase> :

Et quand vous héritez d'une classe, vous surchargez cette méthode, tout se met en place.

Et quelle est la signification de ce CBase ? Et pourquoi faut-il comparer exactement 2 valeurs d'un même type ?

 
Je n'ai pas pour objectif de faire exactement comme en C#, d'ailleurs, je n'ai pas compris en détail comment c'est fait là-bas. Mais à première vue, le IEnumerator de deux fonctions reset et next est très gênant, je ne le copierais certainement pas dans la même forme ;)
 

un casting dynamique pour la comparaison ? Tu es fou ?

une fonction virtuelle pure s'écrit comme suit :virtuelle int CompareTo(Number *par) = 0 ;

c'est le compilateur qui sera maudit et non le substitut d'exception auto-écrit.

 
TheXpert:

une fonction virtuelle pure s'écrit comme suit :virtuelle int CompareTo(Number *par) = 0;

le compilateur sera maudit à la place du substitut d'exception auto-écrit.

Je n'ai pas besoin que le compilateur jure parce que je manipule constamment des classes de type de base (Nombre dans cet exemple). Si le compilateur ne veut pas le faire, le code ne fonctionnera pas du tout.