【超入門】MQL5 EA講座 第44回「参照渡しについて」【EAの作り方】

MQL5でEA作ろう講座

前回は 値渡し について解説しました。

改めて前回の内容をおさらいをしておくと、

  • 値渡しは、関数引数(パラメーター)に、値のコピーを渡す際の記述方法の種類である。

  • 値渡しの場合、データのコピーを渡しているので、関数内での処理がどのようなものであれ、元々の値には一切影響がない

ということをお伝えしました。

今回は 参照渡し についてお話ししたいと思います。

スポンサーリンク
スポンサーリンク

参照渡しとは?

参照渡しも、値渡しと同様に、引数(パラメーター)の記述方法の1つです。

値渡しが、関数引数(パラメーター)に、値のコピーを渡すのに対して、

参照渡しは、関数引数(パラメーター)に、データが格納されている場所を渡しています。

関数

「このデータは、メモリのこの場所にあるから、そこに行ってそのデータ使ってねー ^^) _旦~~」

と言っているわけですね。

これが何を意味するかというと、

値渡し関数に渡すのは元のデータのコピー→元のデータには変化がない。

参照渡し関数に渡すのは元のデータのある場所→元のデータに変化がある!

ということなんです。

コピー機に、コピーしたい情報が書かれた紙をセットして、書かれている情報をコピーしたとします。

仮にコピーした紙をシュレッダーにかけたとしても、セットした元々の紙には何の変化もないですよね?

でも、もしセットした元々の紙をシュレッダーに突っ込んだら、元々の紙言うまでもなく細かく裁断されてしまいます。

値渡し参照渡しの関係もそれと同じで、

値渡し→データのコピーを関数に渡す処理

参照渡し→オリジナルのデータの位置を関数に渡す処理(→オリジナルのデータに変更が生じる可能性がある)

と言う違いがあります。

関数の目的に合わせて引数の記述を値渡しで行うのか、参照渡しで行うのかが設計されています。(自分で関数を作る場合は設計します)

値渡しは、元のデータを使いたいけれども、元のデータが加工・変化することは望まない(=データのコピーだけあれば事足りる)場合に使われるのに対し、

参照渡し関数に渡したデータを加工・変化させたい場合に使います。

参照渡しの記述方法

参照渡し関数引数に値を渡す場合、関数の宣言時、

引数データ型のうしろにアンパサンド(&)を記述します。

戻り値のデータ型 関数名(引数のデータ型 &変数名)//←参照渡しは&がついている!
{

}
--------------------------------------------------------------------------
戻り値のデータ型 関数名(引数のデータ型 変数名)//←&がついていないこれは値渡し!
{

}

前回の値渡しの記事で使ったサンプルコードを参照渡しに修正すると・・・↓


void OnStart()
  {   
     string varString="こんにちわー";
     
    //exampleFuncton関数を呼び出し、引数にvarStringを設定
    exampleFuncton(varString);
    Print(varString);
    
     
  }
  
  //関数「exampleFuncton」を宣言し、仮引数を文字型「passingByValue」に設定
  void exampleFuncton(string &passingByValue)//&をつけて参照渡しにする
  {
      //仮引数「passingByValue」に"こんばんわー"を代入
     passingByValue="こんばんわー";
     
     //ログ出力
     Print(passingByValue);
  }

↑こうなります。

関数「exampleFuncton」の宣言時、引数文字列型データ型の後ろ、変数名「passingByValue」の前 の部分に & をつける事によって、参照渡しに設定します。

値渡しの時から変更したのはここだけです。

void exampleFuncton(string &passingByValue)//&をつけて参照渡しにする

exampleFuncton関数の挙動を値渡しの時と、参照渡しの時で比べたのが下の動画になります。

最初値渡しで、MQL5 Program Fileを実行し、その後参照渡しに変更して再コンパイル→実行してみると・・・

OnStart関数内で宣言している変数「varString」をログ出力してみると、

値渡しの時は初期値の ”こんにちわー”のままで変わらなかったのが、

参照渡しにすることによって、”こんばんわー” に変わっていますね。

参照渡し関数に値を渡すと、元のデータが変更する、ということの意味がお分かりいただけたのではないでしょうか?

配列を参照渡しで渡す

MQL5 EA講座 第42回「return演算子について」

で、基本的に戻り値には、どのデータ型も指定することができるが、return演算子を使って配列全体を返すことはできない

ということを書きました。

じゃあ、関数の処理結果として配列全体を返す手段がないか?というとそんなことはなくて、参照渡しを使うことによって実現できます。

そもそも、配列引数に指定する場合は参照渡しでしか渡すことができない、という文法上の決まりがあるんです。


void OnStart()
  {   
     //setArray関数のための配列を宣言
    double getArray[];
    
    //setArray関数を呼び出し、引数として記述
    setArray(getArray);
    
    //ログ出力→7.2が出力される
    Print(getArray[2]);
     
  }
  
  //setArray関数を宣言し、引数に参照渡しで配列を指定
  void setArray(double &array[])
  {
    //配列のサイズを3にリサイズする
   ArrayResize(array,3);
    
    //配列の各インデックスに値を代入する
    array[0]=1.4;
    array[1]=4.5;
    array[2]=7.2;
  }

順を追ってサンプルコードを見ていきましょう。

グローバル領域(関数の外の領域)に関数を宣言します。

戻り値データ型void戻り値なし)

関数名は 「setArray」

()内の引数データ型double型

参照渡しにするため & をつけて配列名を記述します。(配列名はarray。配列であることを明示する為に最後に[]をつけます)

続いて、{}内の処理実装部分。

ArrayResize関数について

冒頭のArrayResize関数というのは組み込み関数MQL5側で事前に用意されている関数)です。

ArrayResize関数の引数について

ArrayResize関数は、第1引数に記述した配列を、第2引数で指定したサイズに修正する処理を行います。

ArrayResize関数の戻り値について

ArrayResize関数戻り値は、配列の変更後の新しいサイズです。

もし関数が正常に実行された場合、指定した新しいサイズが返されます。

ただし、何らかの理由でサイズ変更が失敗した場合は、-1が返されます。

ArrayResize関数を使う上での注意点

※サイズ変更ができる配列動的配列配列サイズが指定されていない配列)のみです。静的配列では、配列のサイズを宣言時に指定し、その後はサイズを変更することができませんのでご注意ください。

動的配列静的配列に関しては下記の記事をご参照ください。

※プログラミング文脈における「静的」と「動的」という言葉についての詳細は↓の記事をご参照ください

ArrayResize関数とArraySize関数の違い

ArrayResize関数と名前が似た関数として、ArraySize関数があります。

名前こそ似ていますが、関数の役割としては全く異なります。

ArrayResize関数配列のサイズを設定したり変更したりするのに用いるのに対し、

ArraySize関数配列の現在のサイズを取得するために使用されます。

配列のサイズを規定・変更したいのであればArrayResize関数を使い、配列のサイズを確認したいのであればArraySize関数数を使う、という区別をして頂ければと思います。

ArraySize関数については↓のリンク先セクションをご覧ください。

さて、話をサンプルコードの中身に戻します。

サンプルコード中の配列「array」はこの配列サイズを「3」、つまり値を入れられる変数の連なりを3つ用意した、ということを意味します。

配列のサイズを「3」と規定した上で、

1番目の変数→array[0]に1.4、
2番目の変数→array[1]=4.5、
3番目の変数→array[2]=7.2

とそれぞれ初期値代入しました。

これがsetArray関数の全容です。

続いてメインプログラムである、OnStart関数側での処理を見ていきましょう。

setArray関数を稼働させるために、引数にあてがう配列を宣言します。

 //setArray関数のための配列を宣言
    double getArray[];

データ型の種類はdouble型配列名はgetArrayです。配列であることを明示する為に[]をつけます。

続いてsetArray関数を呼び出し、()内に配列「getArray」を記述します。

//setArray関数を呼び出し、引数として記述
    setArray(getArray);

この時、[]は必要ありません。関数の実引数として配列名を記述する時は、[]は付けない仕様になっています。

setArray関数を呼び出したことで、getArray配列配列サイズが「3」にリサイズされ、1~3番目の変数初期値代入されているはずです。

最後に試しに、Print関数でgetArray配列の3番目の変数に格納されている値を確認してみましょう。

 //ログ出力→7.2が出力される
    Print(getArray[2]);

↓の動画を見ると・・・

予想通り「7.2」という結果がログ出力されました。

動的配列と静的配列についてはコチラをご覧ください。

構造体も引数に渡すときは参照渡しで渡す

配列と同様に、参照渡しでしか引数に指定できないものが2つあります。

それが構造体クラスです。

構造体は複数のデータ型変数をひとまとめにしたカスタムデータ型です。

構造体については詳しくは↓の記事をご覧ください。

クラスというのは、まだ一切言及できていませんが、簡単に言うと

変数関数をひとまとめにして扱えるようにした仕組み

のことです。

データを格納する変数と、処理を実行する関数、これらを一元管理できる便利なプログラム概念です。

・・・おそらく現段階では全然ピンとこないと思いますが、後の講座記事で十分解説するのでご安心ください。↓

配列構造体クラス

この3つが、引数に指定する時は参照渡しでしか渡せない、ということだけ今は押さえておいてください。


void OnStart()
  {   
     
     
  }
  
   struct stExample
  {
    int stEx1;
    double stEx2;
    string stEx3;
  };
  
 class exampleClass
 {
   public:
   int num;
 };
  
  //setObject関数を宣言し、引数に参照渡しで配列を指定
  void setObject(exampleClass& ex)
  {
    
  }
 

↑のサンプルコードでは、極めて単純な構造体クラスを宣言して、それを関数引数に記述することを目的としたものです。

このサンプルコードを最初は、値渡しコンパイルしようとすると

「objects are passed by reference only(オブジェクト参照渡しによってのみ渡されます)」というコンパイルエラーが発生します。

コンパイルエラーを受けて、参照渡しで記述をし直して再コンパイルをすると、エラーが解消された・・・というのが下の動画です。

補足

最後にいくつか細かい参照渡しについての補足をしたいと思います。

補足その1:参照渡しで引数に指定できる配列は動的配列のみ

参照渡し引数配列を設定しようとするとき、指定できるのは動的配列のみです。

静的配列を指定しようとすると、“parameter can be a dynamic array only”「動的配列のみが引数に指定できます」というコンパイルエラーが発生します。↓

補足その2:引数のデータ型の後ろにアンパサンド(&)について

参照渡しの際、引数データ型の後ろにアンパサンド(&)をつける訳ですが、データ型の後ろであれば(1)データ型の後ろにくっつける、(2)変数の前にくっつける、(3)どちらからも半角スペース以上を置いて独立して書く、 のどれでも構いません

まとめ

今回は 参照渡し について解説しました。

今回の記事では以下のことを学びました

  • 参照渡しは、関数引数(パラメーター)に、データが格納されている場所を渡している

  • 参照渡しは、関数に元のデータのある場所(アドレス)を渡すので、元のデータが変わる可能性がある。

今回は以上になります。

最後までお読みいただきありがとうございました<m(__)m>

【超入門】MQL5 EA講座 第43回「値渡しについて」【EAの作り方】

      →【超入門】MQL5 EA講座 第45回「関数のオーバーロード」【EAの作り方】

コメント

タイトルとURLをコピーしました