パラメータの引き渡し

機械語がサブプログラム(関数)に引数を渡す方法は 2 つあります。1 番目の方法はパラメータの値渡しです。この方法では、引数値が仮関数引数に複製されます。従って、関数内でのこのパラメータの変更は、対応する呼び出しの引数に影響を及ぼしません。

//+------------------------------------------------------------------+
//| パラメータの値渡し                                                     |
//+------------------------------------------------------------------+
double FirstMethod(int i,int j)
 {
  double res;
//---
  i*=2;
  j/=2;
  res=i+j;
//---
  return(res);
 }
//+------------------------------------------------------------------+
//| スクリプトプログラムを開始する関数                                          |
//+------------------------------------------------------------------+
void OnStart()
 {
//---
  int a=14,b=8;
  Print("a and b before call:",a," ",b);
  double d=FirstMethod(a,b);
  Print("a and b after call:",a," ",b);
 }
//--- スクリプト実行の結果
//  a and b before call: 14 8
//  a and b after call: 14 8

2 番目の方法は、参照渡しです。この場合、(値でなく)パラメータへの参照が関数パラメータに渡されます。それが、関数の内部で、呼び出しで指定された実際のパラメータを参照するために使用されます。従って、パラメータの変更は関数の呼び出しに使用される引数に影響を与えます。

//+------------------------------------------------------------------+
//| パラメータの参照渡し                                                   |
//+------------------------------------------------------------------+
double SecondMethod(int &i,int &j)
 {
  double res;
//---
  i*=2;
  j/=2;
  res=i+j;
//---
  return(res);
 }
//+------------------------------------------------------------------+
//| スクリプトプログラムを開始する関数                                          |
//+------------------------------------------------------------------+
void OnStart()
 {
//---
  int a=14,b=8;
  Print("a and b before call:",a," ",b);
  double d=SecondMethod(a,b);
  Print("a and b after call:",a," ",b);
 }
//+------------------------------------------------------------------+
//--- スクリプト実行の結果
//  a and b before call: 14 8
//  a and b after call: 28 4

MQL5 言語では、配列、構造型の変数やクラスオブジェクトは常に参照によって渡されますが、その例外を除いて両方法が使用されます。実際のパラメータ(関数呼び出しで渡される引数)の変化を避けるには const アクセス指定子を使用します。const 指定子で宣言された変数の内容を変更しようとするとコンパイラがエラーを生成します。

注意事項

パラメータは逆の順序で関数に渡されること、すなわち、最後のパラメータが最初に計算されて、最後から 2 つ目のパラメータが次に計算されて引き渡されることには留意すべきです。最後に計算されて渡されたパラメータは、括弧を開いた後の最初のパラメータです。

例:

void OnStart()
 {
//---
  int a[]={0,1,2};
  int i=0;
 
  func(a[i],a[i++],"First call (i = "+string(i)+")");
  func(a[i++],a[i],"Second call (i = "+string(i)+")");
// 結果:
// First call (i = 0) : par1 = 1     par2 = 0
// Second call (i = 1) : par1 = 1     par2 = 1
 
 }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void func(int par1,int par2,string comment)
 {
  Print(comment,": par1 = ",par1,"    par2 = ",par2);
 }

最初の呼び出し(上記の例を参照)では、i 変数は最初に文字列の連結に使用されます。

 "First call (i = "+string(i)+")"

ここではその値は変更されません。その後 i 変数は a[i++] 配列要素の計算に使用されます。インデックス付き配列要素iがアクセスされた時、i 変数は 増加されます。そしてこの後初めて最初のパラメータが変更された i の値をもって計算されます。

2 番目の呼び出しでは、同じ i の(関数呼び出しの最初の段階で計算された)値が 3 つのパラメータの全てを算出する際に使用されます。最初のパラメータが算出された後で初めて i 変数がもう一度変更されます。

参照

変数のアクセス権スコープとライフタイム オーバーロード仮想関数ポリモーフィズム