如何重写CObject中的Compare(),使CList sort()工作?

 

我找不到任何关于如何在mql5中实现Lists的排序的文档。我看到CList 从CObject指针中调用 Compare()。那么,我怎样才能从父指针中调用子类的Compare()重写方法呢?

例子。

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

我想通了,但我把解决方案留在这里,以防其他人遇到同样的问题。

我忘了在方法覆盖后加上关键字 "const",从而改变了它的签名。

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

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

我想通了,但我把解决方案留在这里,以防其他人遇到同样的问题。

我忘了在方法覆盖后加上关键字 "const",从而改变了它的签名。

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

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

为此,你必须在覆盖方法时使用关键字 "override",这样,如果方法的签名改变了,编译器就会大喊。

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

因为 "const "的不同,它不会被编译。

 

而且你还忘记了这两种情况下的 "虚拟 "关键词。

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

而且你还忘记了这两种情况下的 "虚拟 "关键词。

virtual int            Compare(const CObject *node,const int mode=0) override const;
不......我不希望这个子程序被任何可能的派生程序覆盖。我漏掉了const来使其工作,而覆盖是为了与编译器确认
 
nicholishen:
不......我不希望孩子被任何可能的派生覆盖。我错过了const来使其工作,覆盖是为了与编译器确认。
是的,但至少在CObject 中你需要虚拟关键字
 
Amir Yacoby:
是的,但至少在CObject中你需要虚拟关键词。
我知道了...我没有乱用库中的基类,它默认有这个功能,但你是对的。谢谢你的重写提示!
 
nicholishen: 不......我不希望这个子类被任何可能的派生类重写。
  1. 不添加虚拟 是不好的做法,但不是必须的(除了在CObject 中。)
  2. 不添加virtual 不会改变什么,它仍然可以在派生类中被重写。
  3. MT4/5没有final 关键字
 
whroeder1:
  1. 不添加虚拟 是不好的做法,但不是必须的(除了在CObject中。)
  2. 不添加virtual 不会改变什么,它仍然可以在派生类中被重写。
你错了,whroeder1。
不在基类中添加virtual将导致你失去多态性--该方法将被静态地调用,而不是在运行时动态地调用。

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();
  }
如果a类中的Sub没有virtual,那么任何具有实际b引用的a类型的指针在运行时都不会调用b.Sub()。
 
Amir Yacoby:
你错了,whroeder1。
不在基类中添加virtual将导致你失去多态性--方法将被静态地调用,而不是在运行时动态地调用。

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();
  }
如果a类中的Sub没有虚拟,那么任何有实际b引用的a类型的指针在运行时都不会调用b.Sub()。
正确。同样省略virtual意味着派生类可以覆盖,但不会被父类指针调用。
 
nicholishen:
正确。另外,省略virtual意味着派生类可以覆盖,但不会被父指针调用。
这正是我给出的例子(:a是父类,它调用a.sub而不是b.sub。