Download MetaTrader 5

How to override Compare() in CObject so CList sort() works?

To add comments, please log in or register
nicholishen
1538
nicholishen  

I can't find any documentation on how to implement the sorting of Lists in mql5. I see that CList calls the Compare() from the CObject pointer. So how can I call the child class Compare() overridden method from the parent pointer? 

Example:

 

#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());
      
   }
  
}


 

nicholishen
1538
nicholishen  

I figured it out, but I'm leaving the solution here in case anyone else runs into the same problem.

 

I forgot to and the keyword const after the method override which changed its signature.

 

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

 

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

I figured it out, but I'm leaving the solution here in case anyone else runs into the same problem.

 

I forgot to and the keyword const after the method override which changed its signature.

 

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

 

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

for this you have to use the keyword 'override' always when you override methods, this way the compiler shouts if the method signature is changed:

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

 it won't compile because of the 'const' difference

Amir Yacoby
1354
Amir Yacoby  

And you also forgot the 'virtual' keyword on both cases:

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

And you also forgot the 'virtual' keyword on both cases:

virtual int            Compare(const CObject *node,const int mode=0) override const;
No... I don't want the child to be overridden by any possible derived. I missed const to make it work, and override to confirm with compiler
Amir Yacoby
1354
Amir Yacoby  
nicholishen:
No... I don't want the child to be overridden by any possible derived. I missed const to make it work, and override to confirm with compiler
Yes, but at least in CObject you need the virtual keyword
nicholishen
1538
nicholishen  
Amir Yacoby:
Yes, but at least in CObject you need the virtual keyword
I got ya... I don't mess with the base classes in the library and it has it by default, but you're correct. Thanks for the override tip!
whroeder1
17074
whroeder1  
nicholishen: No... I don't want the child to be overridden by any possible derived.
  1. Not adding the virtual is bad practice, but not required (except in the CObject.)
  2. Not adding the virtual changes nothing, it still can be overridden in a derived class.
  3. MT4/5 doesn't have a final keyword
Amir Yacoby
1354
Amir Yacoby  
whroeder1:
  1. Not adding the virtual is bad practice, but not required (except in the CObject.)
  2. Not adding the virtual changes nothing, it still can be overridden in a derived class.
You are wrong here, whroeder1.
Not adding virtual in the base will cause you loosing the polymorphism - the method will be called statically and not dynamically at run time.

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();
  }
if Sub in class a does not have the virtual, then any pointer of type a that has an actual b reference will never call the b.Sub() at run time.
nicholishen
1538
nicholishen  
Amir Yacoby:
You are wrong here, whroeder1.
Not adding virtual in the base will cause you loosing the polymorphism - the method will be called statically and not dynamically at run time.

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();
  }
is Sub in class a does not have the virtual, then any pointer of type a that has an actual b reference will never call the b.Sub() at run time.
Correct. Also omitting virtual means that derived class can override, but won't be called from a parent pointer.
Amir Yacoby
1354
Amir Yacoby  
nicholishen:
Correct. Also omitting virtual means that derived class can override, but won't be called from a parent pointer.
which is exactly the example I gave (: a is the parent, and it calls a.sub and not b.sub.
To add comments, please log in or register