Wie zu überschreiben Compare() in CObject so CList sort() funktioniert?

 

Ich kann keine Dokumentation darüber finden, wie man die Sortierung von Listen in mql5 implementiert. Ich sehe, dass CList die Methode Compare() vom CObject-Zeiger aufruft. Wie kann ich also die überschriebene Methode Compare() der Kindklasse vom übergeordneten Zeiger aus aufrufen?

Beispiel:

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

Ich habe es herausgefunden, aber ich lasse die Lösung hier, für den Fall, dass jemand anderes auf das gleiche Problem stößt.

Ich habe vergessen, und das Schlüsselwort const nach der Methode überschreiben, die seine Signatur geändert.

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

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

Ich habe es herausgefunden, aber ich lasse die Lösung hier, für den Fall, dass jemand anderes auf das gleiche Problem stößt.

Ich habe vergessen, und das Schlüsselwort const nach der Methode überschreiben, die seine Signatur geändert.

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

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

Dafür muss man immer das Schlüsselwort 'override' verwenden, wenn man Methoden überschreibt, so dass der Compiler schreit, wenn die Signatur der Methode geändert wird:

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

es wird nicht kompiliert, weil der Unterschied 'const' ist

 

Außerdem haben Sie in beiden Fällen das Schlüsselwort "virtuell" vergessen:

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

Außerdem haben Sie in beiden Fällen das Schlüsselwort "virtuell" vergessen:

virtual int            Compare(const CObject *node,const int mode=0) override const;
Nein... Ich will nicht, dass das Kind von einem möglichen abgeleiteten überschrieben wird. Ich vermisste const, damit es funktioniert, und override, um mit Compiler zu bestätigen
 
nicholishen:
Nein... Ich will nicht, dass das Kind von einem möglichen abgeleiteten überschrieben werden. Ich vermisste const, damit es funktioniert, und override, um mit Compiler zu bestätigen
Ja, aber zumindest in CObject brauchen Sie das virtuelle Schlüsselwort
 
Amir Yacoby:
Ja, aber zumindest in CObject brauchen Sie das virtuelle Schlüsselwort
Ich habe verstanden... Ich habe keine Probleme mit den Basisklassen in der Bibliothek und sie hat es standardmäßig, aber Sie haben Recht. Danke für den Tipp mit den Überschreibungen!
 
nicholishen: Nein... Ich möchte nicht, dass das Kind von einer möglichen abgeleiteten Klasse überschrieben wird.
  1. Das Nichthinzufügen der Virtualität ist schlechte Praxis, aber nicht erforderlich (außer im CObject.)
  2. Das Nichthinzufügen der virtuellen ändert nichts, sie kann immer noch in einer abgeleiteten Klasse überschrieben werden.
  3. MT4/5 hat kein Schlüsselwort final
 
whroeder1:
  1. Das Nichthinzufügen der Virtualität ist schlechte Praxis, aber nicht erforderlich (außer im CObject.)
  2. Das Nichthinzufügen der virtuellen ändert nichts, sie kann immer noch in einer abgeleiteten Klasse überschrieben werden.
Du liegst hier falsch, whroeder1.
Wenn Sie in der Basisklasse kein Virtual hinzufügen, verlieren Sie die Polymorphie - die Methode wird statisch und nicht dynamisch zur Laufzeit aufgerufen.

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();
  }
Wenn Sub in Klasse a keine Virtualität hat, dann wird jeder Zeiger vom Typ a, der eine aktuelle b-Referenz hat, zur Laufzeit niemals b.Sub() aufrufen.
 
Amir Yacoby:
Du liegst hier falsch, whroeder1.
Wenn Sie in der Basis keine Virtualität hinzufügen, verlieren Sie die Polymorphie - die Methode wird statisch und nicht dynamisch zur Laufzeit aufgerufen.

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();
  }
Wenn Sub in der Klasse a keine Virtualität hat, dann wird jeder Zeiger vom Typ a, der eine aktuelle b-Referenz hat, niemals b.Sub() zur Laufzeit aufrufen.
Korrekt. Auch das Weglassen von virtual bedeutet, dass eine abgeleitete Klasse überschreiben kann, aber nicht von einem übergeordneten Zeiger aufgerufen wird.
 
nicholishen:
Richtig. Auch das Weglassen von virtual bedeutet, dass eine abgeleitete Klasse überschreiben kann, aber nicht von einem übergeordneten Zeiger aufgerufen wird.
das ist genau das Beispiel, das ich gegeben habe (: a ist das Elternteil, und es ruft a.sub und nicht b.sub.