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); 私は例としてそこにいくつかのコードをスケッチしましたが、私はあまり多くの文字でフォーラムを混乱させたくないので、本当にそうします。

どうぞ、投稿してください。とにかく、ゴミではなく、議論の対象なのです。しかし、議論がここに移されたそのスレッドでは、不適切でしょう。

 

ok)

//+------------------------------------------------------------------+
//|                                                    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:

ok)

IComparer::Compare(CBase &op1, T &op2) メソッドは、両方の引数が T であるべきなのに、なぜ存在するのでしょう?

 
Alexey Navoykov:

また、IComparer::Compare(CBase &op1, T &op2) メソッドは、両引数がTでなければならないのに、なぜ存在するのでしょうか?

同じ種類のものしか比較できないのでしょうか?私の想定では、そうではない。T==CBase とすると、両引数Tが存在することになる )

 

なるほど、それなら、IComparerクラスはIComparer<T1,T2,CBase>のようになるはずです。 したがって、そのメソッドもそうなります。

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

そして、クラスを継承するときには、まさにこのメソッドをオーバーロードすることになり、すべてがうまくいくことになります。
 
Alexey Navoykov:

なるほど、それならIComparerクラスはIComparer<T1,T2,CBase>のようなものでいいんですね。

そして、クラスを継承するときに、このメソッドをオーバーロードすれば、すべてがうまくいくのです。

そして、このCBaseの意味するところは?また、なぜ1つの型から正確に2つの値を比較しなければならないのでしょうか?

 
C#と全く同じにすることを目標にしているわけではなく、また、C#でどのように行われているのかを詳しく理解しているわけではありません。しかし、resetとnextの2つの関数のIEnumeratorは一見すると非常に不便で、私は絶対に同じフォームでコピーしない )
 

比較のためにダイナミックなキャストを使うなんて、どうかしてるぜ?

純粋な仮想関数は、次のように記述されます -virtual int CompareTo(Number *par) = 0 ;

というのは、呪われるのはコンパイラであり、自分で書いた例外サロゲートではありません。

 
TheXpert:

純粋な仮想関数は、次のように記述されます -virtual int CompareTo(Number *par) = 0;

の場合、自分で書いた例外サロゲートの代わりにコンパイラが呪われることになります。

私は常に基本型クラス(この例ではNumber)を操作しているので、コンパイラが悪態をつく必要はない。コンパイラに悪口を言われると、コードが全く動かなくなる