CList sort()가 작동하도록 CObject에서 Compare()를 재정의하는 방법은 무엇입니까?

 

mql5에서 목록 정렬을 구현하는 방법에 대한 문서를 찾을 수 없습니다. 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 에서는 virtual 키워드가 필요합니다.
 
Amir Yacoby :
예, 하지만 적어도 CObject에서는 virtual 키워드가 필요합니다.
알겠습니다... 라이브러리의 기본 클래스를 엉망으로 만들지 않고 기본적으로 라이브러리에 포함되어 있지만 맞습니다. 오버라이드 팁 감사합니다!
 
nicholishen : 아니요... 나는 그 아이가 어떤 가능한 파생물에 의해 무시되는 것을 원하지 않습니다.
  1. 가상 을 추가하지 않는 것은 나쁜 습관이지만 필수는 아닙니다( CObject 제외).
  2. 가상 변경 사항을 추가하지 않으면 파생 클래스에서 여전히 재정의될 수 있습니다.
  3. MT4/5에는 최종 키워드가 없습니다.
 
whroeder1 :
  1. 가상 을 추가하지 않는 것은 나쁜 습관이지만 필수는 아닙니다(CObject 제외).
  2. 가상 변경 사항을 추가하지 않으면 파생 클래스에서 여전히 재정의될 수 있습니다.
당신은 여기에서 틀렸습니다, whoroeder1.
기본에 가상을 추가하지 않으면 다형성을 잃게 됩니다. 메서드는 런타임에 동적으로 호출되지 않고 정적으로 호출됩니다.

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에 가상이 없으면 실제 b 참조가 있는 유형 a의 포인터는 런타임에 b.Sub()를 호출하지 않습니다.
 
Amir Yacoby :
당신은 여기에서 틀렸습니다, whoroeder1.
기본에 가상을 추가하지 않으면 다형성을 잃게 됩니다. 메서드는 런타임에 동적으로 호출되지 않고 정적으로 호출됩니다.

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()를 호출하지 않습니다.
옳은. 또한 가상을 생략한다는 것은 파생 클래스가 재정의할 수 있지만 부모 포인터에서 호출되지 않는다는 것을 의미합니다.
 
nicholishen :
옳은. 또한 가상을 생략한다는 것은 파생 클래스가 재정의할 수 있지만 부모 포인터에서 호출되지 않는다는 것을 의미합니다.
이것은 정확히 내가 준 예입니다(: 는 부모이고 b.sub가 아니라 a.sub를 호출합니다.