mql5中的OOP、模板和宏,细微之处和用途 - 页 10

 
Alexey Navoykov:

毕竟,继承链可以是你想要的任何东西:甚至是Interface<CBase>,甚至是Interface<C<B<A<CBase>>>>,有大量的变体。我们将不得不把CBase依次投给所有可能的变体,这是不现实的。

我记得我打算实现在类对象 本身中存储接口的信息,除了现有的接口垫之外,还要制作独立的接口类,作为我们的垫的包装。但后来我得出结论,所有这些都是不必要的,是多余的。在实践中,我从未见过需要将基类投给任何接口的情况,这没有任何意义。 唯一的选择是找出该类是否支持这个接口,以达到调试的目的,但我们不需要为此而投。

在我看来,我们应该将接口存储在接口中。Interface<T,CBase>::GetComparer().Compare(CBase &a, T& b); 我在那里勾画了一些代码作为例子,但我真的不想用太多的字母把论坛弄得一团糟。

 
Ilya Malev:

在我看来,接口应该存储在接口本身。Interface<T,CBase>::GetComparer().Compare(CBase &a, T& b); 我在那里勾画了一些代码作为例子,但我真的不想用太多的字母把论坛弄得一团糟。

来吧,发布它。总之,这不是垃圾,而是一个讨论的主题。但在那个讨论被转移到这里的主题中,这将是不恰当的。

 

好的)

//+------------------------------------------------------------------+
//|                                                    Comparer demo |
//|                                      Copyright 2012, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#property strict

#define  throw(M)   {int a=0,b=1; printf("%s: %s",__FUNCSIG__,M); Print(b%a); } 
#define  msg_pure   "Method not implemented!"
#define  msg_compare "Types are uncomparable!"


template<typename T,typename CBase>
class IComparer;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class Number
  {
public:
   virtual int CompareTo(Number *par)
    { 
      throw(msg_pure); return 0; 
    }
   int operator==(Number*par)
    {
      return CompareTo(par);
    }
   template<typename T> 
   T *operator[](T*)
    { 
      return dynamic_cast<T*>(&this); 
    }
   virtual string ToStr()
    { 
      return StringFormat("Type %s, object %i (%i)",typename(this),&this,CheckPointer(&this));
    }
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class Int: public Number
  {
private:
   int               i;
public:
   int Get()
    { 
      return i; 
    }
   Int*Set(int p)
    { 
      i=p; 
      return &this; 
    }
   virtual int CompareTo(Number*par)
     {
      Int*v1=dynamic_cast<Int*>(par);
      if(v1)
       {
        return IComparer<Int,Int>::GetComparer()[ IComparer<Int,Int>::GetComparer() ].Compare( &this,v1 );
       }
      
      Double*v2=dynamic_cast<Double*>(par);
      if(v2)
       {
        return IComparer<Double,Int>::GetComparer()[ IComparer<Double,Int>::GetComparer() ].Compare( &this,v2 );
       }
       
      throw(msg_compare); return 0;
     }
   Int*operator=( int p )
    { 
      return Set( p ); 
    }
   virtual string ToStr()
    { 
      return IntegerToString(i); 
    }
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class Double: public Number
  {
private:
   double            f;
public:
   double Get()
    { 
      return f; 
    }
   Double*Set(double p)
    { 
      f=p; 
      return &this; 
    }
   virtual int CompareTo(Number*par)
     {
      Double*v1=dynamic_cast<Double*>(par);
      if(v1)
       {
        return IComparer<Double,Double>::GetComparer()[ IComparer<Double,Double>::GetComparer() ].Compare( &this,v1 );
       }
       
      Int*v2=dynamic_cast<Int*>(par);
      if(v2)
       {
        return IComparer<Int,Double>::GetComparer()[ IComparer<Int,Double>::GetComparer() ].Compare( &this,v2 );
       }
       
      throw(msg_compare); return 0;
     }
   Double*operator=(double p)
    { 
      return Set(p); 
    }
   virtual string ToStr()
    { 
      return DoubleToString(f,_Digits); 
    }
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
template<typename T,typename CBase>
class IComparer: public CBase
  {
private:
   static IComparer *comparer;
public:
   IComparer()
    { 
      if(!comparer) 
       {
        comparer=&this; 
       }
    }
   virtual int Compare(CBase &op1,T &op2)
    { 
      throw(msg_pure); 
      return 0; 
    }

   static IComparer *GetComparer()
    { 
      return comparer ? comparer : new IComparer; 
    }
   static string ToStr(int cmp)
    { 
      return(!cmp?"equal":(cmp==-1?"lesser than":(cmp==1?"greater than":"undefined"))); 
    }
  };

template<typename T,typename CBase>
IComparer *IComparer::comparer=NULL;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CmpIntToInt: public IComparer<Int,Int>
  {
   virtual int Compare(Int &op1,Int &op2)
    { 
      return(op1.Get()>op2.Get())-(op1.Get()<op2.Get()); 
    }
  }
citi;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CmpIntToDouble: public IComparer<Int,Double>
  {
   virtual int Compare(Double &op1,Int &op2)
    { 
      return int(op1.Get()-op2.Get()>DBL_EPSILON)-int(op2.Get()-op1.Get()>DBL_EPSILON); 
    }
  }
citd;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CmpDoubleToInt: public IComparer<Double,Int>
  {
   virtual int Compare(Int &op1,Double &op2)
    { 
      return int(op1.Get()-op2.Get()>DBL_EPSILON)-int(op2.Get()-op1.Get()>DBL_EPSILON); 
    }
  }
cdti;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CmpDoubleToDouble: public IComparer<Double,Double>
  {
   virtual int Compare(Double &op1,Double &op2)
    { 
      return int(op1.Get()-op2.Get()>DBL_EPSILON)-int(op2.Get()-op1.Get()>DBL_EPSILON); 
    }
  }
cdtd;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   srand(GetTickCount());
   Number *n[10];

   for(int i=0;i<10;i++)
     {
      if(rand()%2==0) n[i]=new Int=rand();
      else            n[i]=new Double=rand()*rand()/(1.0*rand());
     }

   for(int i=0;i<10;i++)
     {
      int a=rand()%10,b=rand()%10;
      printf("%s is %s %s",n[a].ToStr(),IComparer<Int,Int>::ToStr(*n[a]==n[b]),n[b].ToStr());
     }

   for(int i=0;i<10;i++)
     {
      delete n[i];
     }
  }
//+------------------------------------------------------------------+
 
Ilya Malev:

好的)

如果两个参数都是T,为什么IComparer::Compare(CBase &op1, T &op2) 方法会在那里?

 
Alexey Navoykov:

如果两个参数都是T,为什么还有IComparer::Compare(CBase &op1, T &op2) 方法?

是否只能比较相同的类型?我的假设是,它不是。使T==CBase,将有两个参数T )

 

啊,明白了,那你就错了。 在你的例子中,IComparer类应该像IComparer<T1,T2,CBase>。 相应地,方法也会如此。

virtual Compare(T1 &op1, T2 &op2) = 0;

当你继承这个类的时候,你将恰好重载这个方法,一切都将归位。
 
Alexey Navoykov:

啊,我明白了,你完全搞错了。 IComparer类在你的例子中应该是IComparer<T1,T2,CBase>。

而当你继承一个类时,你将重载这个方法,一切都将归位。

那么这个CBase的含义是什么呢?还有,为什么正好有2个同一类型的值必须进行比较?

 
我的目标不是让它和C#完全一样,而且,我还没有详细了解它是怎么做的。但一眼看去,两个函数的IEnumerator的reset和next是非常不方便的,我肯定不会在同一个表格中复制它 )
 

你是疯了吗?

一个纯虚拟函数 是这样写的--虚拟 int CompareTo(Number *par) = 0

被诅咒的是编译器,而不是自写的异常代理。

 
TheXpert:

一个纯虚拟函数 是这样写的--虚拟 int CompareTo(Number *par) = 0

编译器将被诅咒,而不是自写的异常代理。

我不需要编译器发誓,因为我不断地操作基本类型的类(本例中的Number)。如果编译器对它发誓,代码根本不会运行