PLOです。アプリケーションの問題 - ページ 4

 
Yedelkin:

質問です。親クラスで特定のパラメータと型を持つ仮想関数を 宣言した後、子孫クラスで対応する仮想関数のパラメータの数と型を変更することは可能ですか?

一方、リファレンスマニュアルでは、「派生クラスで 仮想関数を代用 することができる」とされています。仮想関数に対してどの 関数定義を 呼び出すかは動的に(実行時に)選択 される。典型的なケースは、ベースクラスがその関数を含み、派生クラスがその関数の独自のバージョンを 持つ場合 です一方、リファレンスマニュアルに記載されている例は、仮想関数が関数定義ヘッダではなく 、関数定義体を 持つ場合について言及しています。

私が記憶している限りでは可能です。ただし、パラメータの種類と数には絶対に気をつけなければならない。

また、渡される値の種類やデフォルト値にも注意が必要です。

ここでは、わかりやすくするために、いくつかの例を挙げています。

このバリアントがあれば大丈夫。

boll MyFunction(int Param);
boll MyFunction(int Param1,int Param2);

これはそうではない(というか、もしかしたら動くかもしれないが、バグやある種の留保がある)。

//Ели второй параметр будет упущен, то компилятор может и не "понять" смысла всего задуманного
boll MyFunction(int Param);
boll MyFunction(int Param1,int Param2 = 0);
//Так тоже может не прокатить по причине совпадения типов у второго параметра
boll MyFunction(int Param1,color Param2);
boll MyFunction(int Param1,int Param2);

クラス内のメソッドを再読み込みした場合も全く同じことが起こります。

 
mql5:
デフォルトの設定を除いた、定義の完全なコピーのみ(デフォルトは異なる場合がありますが、これを使用しないのがベストです)
定義ヘッダーのみの 正確なコピー」ということでしょうか?結局、関数定義には ヘッダーとボディが含まれる。例のボディは確かに違いますね。
 

面白いですね。私の理解では、関数の仮想化と関数のオーバーロードは少し違うものです。また、mql5では、関数仮想化では関数ヘッダのハードコピーが必要だと言っています(デフォルトのパラメータは考慮に入れていません)。

 
Yedelkin:

面白いですね、私の理解では、関数の仮想化と関数のオーバーロードは少し違うものです。また、mql5では、関数の仮想化では、関数ヘッダのハードコピーが必要だと言っています(デフォルトのパラメータは考慮していません)。

> 質問です。親クラスで特定のパラメータとその型を持つ仮想関数を 宣言した後、子孫クラスで対応する仮想関数のパラメータの数と型を変更することは可能ですか?

私の理解が正しければ、子は祖先の機能をオーバーロードする必要があります。

正直なところ、virtualでそんなことをした覚えはないのですが(したような気がする)、オーバーロード云々というのはその通りで、私自身も一度だけその失敗をしたことがあります。

追記

私の理解では、すべてが正しく行われれば、パラメーターの数は増やすことも減らすこともできます。難しいのは、パラメータの数は変わらないのに、その型が変わってしまった場合...。

 

とにかく、この例をスケッチしてみました。

class C_A             //родительский класс
{
 public:
 virtual double function(double a1, double a2, double a3) { return; }
}
class C_B : public C_A
{
 public:
 virtual double function(double a1, double a2, double a3) { return(a1);   }
}
class C_C : public C_A
{
 public:      
 virtual double function(double a1, double a2, double a3) { return(a2);   }
        double function(double a1, double a2)           { return(a1+a2); }
}
//где-то в программе объявляем указатель
C_A  *pointer;
int random=rand()%2;
   switch(random)
     {
      case 0: pointer=new C_B; break;
      case 1: pointer=new C_C; break;
     }

//вызываем виртуальный метод
   if(pointer!=NULL)
     {
      pointer.function(a1,a2,a3);
     }

C_Cクラスで関数メソッドがオーバーロードされているかどうかに関係なく、仮想関数は ポインタ.function(a1,a2,a3)という3つのパラメータだけで呼び出せることが判明した。これに対応して、プログラムは仮想関数を呼び出す際に、C_C クラスから 2 パラメータのメソッドに辿り着くことはない。そうだろ?

 
Yedelkin:

とにかく、この例をスケッチしてみました。

C_Cクラスで関数メソッドがオーバーロードされているかどうかに関係なく、仮想関数は ポインタ.function(a1,a2,a3)という3つのパラメータだけで呼び出せることが判明した。これに対応して、プログラムは仮想関数を呼び出す際に、C_C クラスから 2 パラメータのメソッドに辿り着くことはない。そうだろ?

コンストラクタやデストラクタの印字に__FUNCTION__マクロを挿入して、プログラムが何を行っているかを分析すると、非常に便利です。

また、基底クラスへのポインタを宣言することで、基底クラスを経由した子孫への「トンネル」が構築されることも付け加えておく。したがって、この方法で子孫を呼び出すと、コンパイラはベースクラスで宣言された関数だけを見ることになる。子孫オブジェクトを直接宣言すれば(同じプログラム内でも)、すべての機能がそのオブジェクトで利用できるようになります。

class C_A             //родительский класс
{
 public:
 virtual double function(double a1, double a2, double a3) { return; }
}
class C_B : public C_A
{
 public:
 virtual double function(double a1, double a2, double a3) { return(a1);   }
}
class C_C : public C_A
{
 public:      
 virtual double function(double a1, double a2, double a3) { return(a2);   }
        double function(double a1, double a2)           { return(a1+a2); }
}
//где-то в программе объявляем указатель
C_A  *pointer;
int random=rand()%2;
   switch(random)
     {
      case 0: pointer=new C_B; break;
      case 1: pointer=new C_C; break;
//вызываем виртуальный метод
   if(pointer!=NULL)
     {
      pointer.function(a1,a2,a3);
     }
C_С  *new_pointer=new C_C;
      new_pointer.function(a1,a2);
 
Yedelkin:

とにかく、この例をスケッチしてみました。

C_Cクラスで関数メソッドがオーバーロードされているかどうかに関係なく、仮想関数は ポインタ.function(a1,a2,a3)という3つのパラメータだけで呼び出せることが判明した。これに対応して、プログラムは仮想関数を呼び出す際に、C_C クラスから 2 パラメータのメソッドに到達することはない。そうだろ?

私自身の経験から、次のような方法でコードをパックすることをお勧めします。

double function(double a1, double a2)            {return(a1+a2);}
double function(double a1, double a2, double a3) {return(a2);}

そして、添付のファイルを例として、エンターテイメントとしてご覧いただけます。

ポインタやnewを使うのは面倒なので、単純にワーキングクラスを変数として宣言しました。

Expert Advisorは、0/1の乱数を等間隔で発生させ、その結果に応じてMarketBuy/MarketSellの2つの機能のいずれかを実行します。


必要であれば、このようにすることができます

bool MarketBuy(string SymbolTitle,double LotSize,double TP = 0.0,double SL = 0.0);
bool MarketSell(string SymbolTitle,double LotSize,double TP = 0.0,double SL = 0.0);

との競合により、バグが発生する可能性があります。

bool MarketBuy(string SymbolTitle,double LotSize);
bool MarketSell(string SymbolTitle,double LotSize);


追記

手作業で作ったので、不正確な部分があるかもしれません。

しかし、基本的な考え方は理解することができます。

ファイル:
Forum.mq5  18 kb
 

貴重なアドバイスやご指導をいただき、本当にありがとう ございました必ず使いますが、理論と実践の両方に十分な時間があればと思います。

Interesting:

私自身の経験から、私はコードを完了するようにお勧めすることができます。

double function(double a1, double a2)            {return(a1+a2);}
double function(double a1, double a2, double a3) {return(a2);}
なぜこの方法なのか?落とし穴は何ですか?
 
Yedelkin:

なぜ、そんなふうになるのでしょうか。落とし穴は何ですか?

昔はそれで問題があったんだと思います。でも、今となってはどれがどれだか思い出せません。

とにかく、慣れました。

通常、もちろん違いはありませんが、少なくとも私の例では、場所を入れ替えてみたらすべてうまくいきました...。

 
Interesting:

昔はそれで問題があったんだと思います。でも、今となってはどれがどれだか思い出せません。

なるほど、いずれにせよ--心に留めておくことにします。