OOP, modelos e macros em mql5, sutilezas e usos - página 10

 
Alexey Navoykov:

Afinal, a cadeia sucessória poderia ser tudo o que você quiser: mesmo Interface<CBase>, mesmo Interface<C<B<A<CBase>>>>, há toneladas de variantes. Teríamos que lançar CBase seqüencialmente para todas as variantes possíveis, o que é irrealista.

Lembro-me que eu ia implementar o armazenamento de informações sobre interfaces no próprio objeto de classe e, além dos blocos de interface existentes, fazer classes de interface independentes que funcionariam como um invólucro sobre nosso bloco. Mas então cheguei à conclusão de que tudo isso era desnecessário e desnecessário. Na prática, eu nunca vi a necessidade de lançar uma classe base para qualquer interface, simplesmente não faz sentido. A única opção é descobrir se a classe suporta esta interface para fins de depuração, mas não precisamos de fundição para isso.

Na minha opinião, deveríamos armazenar a interface na interface. Interface<T,CBase>::GetComparer().Compare(CBase &a, T& b); eu esbocei algum código lá por exemplo, mas eu realmente não quero desorganizar o fórum com muitas letras.

 
Ilya Malev:

Na minha opinião, a interface deveria ser armazenada na própria interface. Interface<T,CBase>::GetComparer().Compare(CBase &a, T& b); eu esbocei algum código lá por exemplo, mas eu realmente não quero desorganizar o fórum com muitas letras.

Vá em frente e afixe isso. De qualquer forma, não se trata de lixo, mas de um assunto de discussão. Mas, nesse fio a partir do qual a discussão foi transferida para cá, seria inapropriado.

 

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)

Por que aIComparer::Compare(CBase &op1, T &op2) método lá se ambos os argumentos devem ser T

 
Alexey Navoykov:

E por que láIComparer::Compare(CBase &op1, T &op2) método se ambos os argumentos devem ser T

Só é possível comparar os mesmos tipos? Minha suposição é que não é. Faça T==CBase e haverá ambos os argumentos T )

 

Ah, entendi, então você entendeu tudo errado. A classe IComparer em seu caso deveria ser como IComparer<T1,T2,CBase>. Assim, o método também será:

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

E quando você herdar a classe você irá sobrecarregar exatamente este método, tudo se encaixará no lugar.
 
Alexey Navoykov:

Ah, estou vendo, então você entendeu tudo errado. A classe IComparer em seu caso deveria ser como IComparer<T1,T2,CBase>:

E quando você herda uma classe, você sobrecarrega este método, tudo se encaixa no lugar.

E qual é o significado deste CBase? E por que exatamente dois valores de um tipo devem ser comparados?

 
Não tenho um objetivo de fazer exatamente como em C#, além disso, não entendi em detalhes como é feito lá. Mas num relance o IEnumerador de duas funções reiniciadas e o próximo é muito inconveniente, eu definitivamente não o copiaria na mesma forma )
 

elenco dinâmico para comparação? você está fora de si?

uma função puramente virtual é escrita assim -virtual int CompareTo(Número *par) = 0 ;

é o compilador que será amaldiçoado e não o substituto da exceção autoescrita.

 
TheXpert:

uma função puramente virtual é escrita assim -virtual int CompareTo(Número *par) = 0;

o compilador será amaldiçoado ao invés do substituto da exceção autoescrita.

Eu não preciso do compilador para jurar porque eu manipulo constantemente as classes do tipo base (Número neste exemplo). Se o compilador jurar, o código não funcionará de forma alguma