Como substituir a comparação() em CObject para que a classificação CList() funcione?

 

Não consigo encontrar nenhuma documentação sobre como implementar a ordenação de Listas em mql5. Vejo que a CLIST chama a Comparação() a partir do ponteiro CObjeto. Então, como posso chamar a classe criança de Compare() a partir do ponteiro dos pais?

Exemplo:

#include <Arrays\List.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

class PriceScore : public CObject
{
protected:
   int price;
   int score;
public:
                  PriceScore(void){}
                  PriceScore(int p, int s):price(p),score(s){}
                  ~PriceScore(void){}
   int            Compare(const CObject *node,const int mode=0);
   void           Price(const int p){price = p;}
   int            Price() const {return price;}
   void           Score(const int s){score = s;}
   int            Score() const {return score;}
  
};
int PriceScore::Compare(const CObject *node,const int mode=0) //Can't call this override from CList
{
   PriceScore *pc = (PriceScore*)node;
   Print(__FUNCTION__,":Compare called. Incoming: ",pc.Score()," This: ", score); //Doesn't log because this isn't called from CObject'
   if(pc.Score()< score)return 1;
   else if(pc.Score()> score) return -1;
   else return 0;
}

void OnStart()
  {
//---
   CList list;

   list.Add( new PriceScore(100,500));
   list.Add( new PriceScore(1,5));
   list.Add( new PriceScore(13,5000));
   list.Add( new PriceScore(987987,567));
   list.Add( new PriceScore(98798778,1));
  
   PriceScore *node = NULL;
   Print("-------------------",TimeCurrent(),"--------------------");
   for(int i=0;i<list.Total();i++)
   {
      node = list.GetNodeAtIndex(i);
      Print("Price = ",node.Price(),", Score = ",node.Score());
      
   }
   list.Sort(1); //Can't call overriden child method'
  
  
   Print("-------------------SORTED--------------------");
   for(int i=0;i<list.Total();i++)
   {
      node = list.GetNodeAtIndex(i);
      Print("Price = ",node.Price(),", Score = ",node.Score());
      
   }
  
}
 

Eu descobri, mas vou deixar a solução aqui, caso alguém mais se depare com o mesmo problema.

Eu esqueci e a palavra-chave const após a substituição do método que mudou sua assinatura.

int            Compare(const CObject *node,const int mode=0);

int            Compare(const CObject *node,const int mode=0) const;
 
nicholishen:

Eu descobri, mas vou deixar a solução aqui, caso alguém mais se depare com o mesmo problema.

Eu esqueci e a palavra-chave const após a substituição do método que mudou sua assinatura.

int            Compare(const CObject *node,const int mode=0);

int            Compare(const CObject *node,const int mode=0) const;

para isto você tem que usar a palavra-chave 'override' sempre quando você sobrepõe métodos, desta forma o compilador grita se a assinatura do método for alterada:

int            Compare(const CObject *node,const int mode=0) override const;

ele não compilará por causa da diferença 'const'.

 

E você também esqueceu a palavra-chave "virtual" em ambos os casos:

virtual int            Compare(const CObject *node,const int mode=0) override const;
 
Amir Yacoby:

E você também esqueceu a palavra-chave "virtual" em ambos os casos:

virtual int            Compare(const CObject *node,const int mode=0) override const;
Não... Eu não quero que a criança seja substituída por nenhuma derivação possível. Perdi Const para que funcionasse, e anulá-lo para confirmar com o compilador
 
nicholishen:
Não... Eu não quero que a criança seja substituída por nenhuma derivação possível. Perdi Const para que funcionasse, e anulá-lo para confirmar com o compilador
Sim, mas pelo menos no CObject você precisa da palavra-chave virtual
 
Amir Yacoby:
Sim, mas pelo menos no CObject você precisa da palavra-chave virtual
Eu te peguei... Eu não mexo com as classes base da biblioteca e ela a tem por padrão, mas você está correto. Obrigado pela dica de anulação!
 
nicholishen: Não... Eu não quero que a criança seja substituída por nenhuma derivação possível.
  1. Não adicionar o virtual é uma má prática, mas não é necessário (exceto no CObjeto).
  2. Não adicionar o virtual não muda nada, ele ainda pode ser anulado em uma classe derivada.
  3. O MT4/5 não tem uma palavra-chave final
 
whroeder1:
  1. Não adicionar o virtual é uma má prática, mas não é necessário (exceto no CObjeto).
  2. Não adicionar o virtual não muda nada, ele ainda pode ser anulado em uma classe derivada.
Você está errado aqui, whroeder1.
Não adicionar virtual na base fará você perder o polimorfismo - o método será chamado estaticamente e não dinamicamente em tempo de execução.

class a
{
public:
   void Sub()
     {
      Print("a.sub");
     }
};
class b : public a
{
public:
   void Sub()
     {
      Print("b.sub");
     }
};
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   clsa *a;
   clsa=new b;
   clsa.Sub();
  }
se Sub na classe a não tiver o virtual, então qualquer ponteiro do tipo a que tenha uma referência b real nunca chamará o b.Sub() em tempo de execução.
 
Amir Yacoby:
Você está errado aqui, whroeder1.
Não adicionar virtual na base fará você perder o polimorfismo - o método será chamado estaticamente e não dinamicamente em tempo de execução.

class a
{
public:
   void Sub()
     {
      Print("a.sub");
     }
};
class b : public a
{
public:
   void Sub()
     {
      Print("b.sub");
     }
};
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   a *clsa;
   clsa=new b;
   clsa.Sub();
  }
é Sub na classe a não tem o virtual, então qualquer ponteiro do tipo a que tenha uma referência b real nunca chamará o b.Sub() em tempo de execução.
Correto. Omitir também o virtual significa que a classe derivada pode anular, mas não será chamada a partir de um ponteiro pai.
 
nicholishen:
Correto. Omitir também o virtual significa que a classe derivada pode se sobrepor, mas não será chamada de um ponteiro pai.
que é exatamente o exemplo que dei (: a é o pai, e ele chama a.sub e não b.sub.
Razão: