関数のオーバーロードとは?
関数のオーバーロードとは、
関数に複数の書式を付与すること
を言います。
例えば、洗濯機があったとします。
最近の洗濯機は、「お急ぎモード」とか「泥んこモード」とか「ソフトモード」みたいに目的と投入する洗濯物の種類によって、いろんなモードが選択出来たりますよね?
いちいち目的に合わせて、何台も何台も洗濯機を買うようなことをしていたら、お金とスペースがいくらあっても足りません。(>_<)
関数もそれと同じで、
基本的には同じ処理をしたり、同じ計算結果を返すけど、その小さな違いのためにいちいち違う関数を作っていると、関数ばかりが増えて管理が行き届かななくなってしまいます。
MQL5では、同じ名前の関数でも、複数の異なる処理を行うことができるような仕組みを設けています。
それがオーバーロードという訳です。
関数をオーバーロードさせる(関数に複数の書式を付与する)方法
関数に複数の書式を付与するには
もしくは
2.引数の数を変える
もしくは
3. 1と 2、その両方を組み合わせる
のどれかの条件を満たす必要があります。
引数のデータ型とその数が同一の場合コンパイルが通りません(その場合、戻り値のデータ型を変えても駄目です)
double testFunction(double x,int y)
{
double ex=0;
return ex;
}
int testFunction(double x,int y)
{
int ex=0;
return ex;
}
↑の例では、testFunctionという同名の関数が2つあります。
どちらもdouble型の引数が1つ、int型の引数が1つ、とまったく同じ引数構成になっています。これだとコンパイルエラーになります。
double testFunction(double x,int y)
{
double ex=0;
return ex;
}
int testFunction(int x,int y)
{
int ex=0;
return ex;
}
↑2つ目のtestFunction関数の第1引数をint型からdouble型にしました。
となりました。
これでコンパイルは通ります。
double testFunction(double x,int y)
{
double ex=0;
return ex;
}
int testFunction(double x,int y,string z)
{
int ex=0;
return ex;
}
↑の場合、
第2書式の引数構成→(double型,int型,string型)
となりました。
第1引数と第2引数までは同じ引数構成ですが、第2書式には第3引数が足されて引数の構成が異なるので、コンパイルは通ります。
double testFunction(double x,int y)
{
double ex=0;
return ex;
}
int testFunction(int x,double y)
{
int ex=0;
return ex;
}
↑のケースでは
となっています。
引数の数は2つで、引数のデータ型内訳もint型1つ,double型つとなっています。
ですが、()内の引数のデータ型の順番が異なっているので、これはコンパイルが通ります。
関数のオーバーロードの使用例(組み込み関数編)
ここまでで、
関数のオーバーロード(関数書式の多重化)
についてのルールをひとしきり解説してきました。
それでは次に、
MQL5の組み込み関数の中でオーバーロード関数になっているものを見てみましょう。
ArrayInitialize関数
ArrayInitialize関数という関数があります。
最初にこの関数の機能について説明します。
第1引数に配列を指定し、第2引数に初期化する値を入力します。
各配列に格納されている値は第2引数に入力した値に初期化されます。↓
void OnStart()
{
//配列を宣言し初期値を代入
int array[5]={1,2,3,4,5};
//ループチェック
for(int icounter=0; icounter<5 ;icounter++)
{
//ログ出力
Print("配列["+(string)icounter+"]=",array[icounter]);
}//1,2,3,4,5がログ出力
//配列の値を0に初期化
ArrayInitialize(array,0);
//ループチェック
for(int icounter=0; icounter<5 ;icounter++)
{
//ログ出力
Print("配列["+(string)icounter+"]=",array[icounter]);
}//0,0,0,0,0がログ出力
}
配列サイズが5の配列arrayを宣言し、5個ある配列の要素に初期値をそれぞれ1,2,3,4,5と代入します。
※配列についての基礎は↓の記事をご参照ください
この時点でfor文を使い、配列に格納されている値をPrint関数でログ出力すると
※for文についての詳細は↓の記事をご参照ください
その後、ArrayInitialize関数を使って、配列全体の値を「0」に初期化して更新しました。
再度配列に格納されている値をPrint関数でログ出力すると、すべての配列の要素が0になっています。
MQL5 Program Fileを実行して確認してみても↓
予想通りの結果になっています。
※Print関数の()内に記述でループ変数であるicounterの前に
(string)という記述がありますが、これは型変換(キャスト)と呼ばれるものです。
詳しくは↓
をご覧ください。
で、ここからがようやくオーバーロード(関数書式の多重化)の話になるんですが、
ArrayInitialize関数の書式は実に8つあります!
メタエディターでは、組み込み関数名を最初の何文字か入力するとオートコンプリーション機能が働き、設定されている書式一覧が提示されるようになっているのですが、こんな風に出てきます。↓
書式が8つもある理由は、配列宣言時のデータ型と、初期化するデータ型を一致させるためです。
例えば、int型の値を入れる為に用意した配列に、1.5とかの実数型(double型)の値を入れることはデータの欠損を招く恐れがあるので、推奨されません。
オーバーロードの関数にて、どの書式が選択されたのかは、プログラマーが記述した内容に応じて、コンパイル時に自動選択されます。
各データ型の違いについては以下のリンクから該当記事をご覧ください。
関数のオーバーロードの使用例(自作関数編)
自分で、オリジナルの関数を作るときに、オーバーロード(関数書式の多重化)をどう利用するか?
という問題なんですが、これは、これから作るEAの設計方針に応じて色々な使い方ができると思います。
例えば、
エントリーする際のロットをどのくらいのボリュームに設定するのか?
というのはトレード戦略において重要な割合を占めると私は思っていますが、そのロット算出を担う関数を、私はオーバーロード(関数書式の多重化)させています。
//書式1
double MoneyManagement(
string pSymbol,//対象通貨ペア
double pFixedVol,//固定ロットモード時のロット数
double pPercent,//可変ロットモード時の残高に対する許容損失割合
int pStopPoints//ポイントベースでの損切り値
)
{
//実装記述は省略
}
//--------------------------------------------------------------------------
//書式2
double MoneyManagement(bool pAssetMode,//アセットモードのONOFF
double pAssetModeMultiplier,//アセットモードの乗数
double pMaxAsset,//最大口座残高
string pSymbol,//対象通貨ペア
double pFixedVol,//固定ロットモード時のロット数
double pPercent,//可変ロットモード時の残高に対する許容損失割合
int pStopPoints,//ポイントベースでの損切り値
double pPreviousVolume,//直近決済の初弾ロット
double pMostRecentPL,//直近決済の損益
double pDecreasePer,勝ちトレード後の減ロット計算
int pConsectiveWin,//連勝数
double pIncreasePer,//増ロット計算
int pConsectiveLose,//連敗数
double pMinLot=0.01,//最小ロット数
double pRiskyLot=2.0,//リスク感知ロット数
double pRiskRestrainPer=0.3//リスク抑制ロット数
)
{
//実装記述は省略
}
↑のように、
書式1については、引数が4つなのに対し、
書式2では引数が16と大幅に増えていますね。
細かい引数の役割や、関数の実装記述詳細は割愛させていただきますが、
書式1では、固定ロットモード時のロット数、可変ロット時のリスクにさらす割合、損切りポイントぐらいなのに対し、
書式2では、固定ロットモード、可変ロットモードに加えて、直近の取引状況や残高の増減状況に応じてロット数を調整したり、相場状況に応じてリスクにさらす割合を変えたりするモードを搭載したより細かい設定を盛り込んでいます。
これらの引数を多くは、input変数で制御できるようにしています。
関数をオーバーロード(関数書式の多重化)させることによって、より関数を管理しやすく、かつ柔軟に利用・運用できるという訳です。
おまけ
おまけその1-バリアントという言葉について-
関数に複数の書式を付与することである、
と本編で解説してきましたが、その際の各書式を「バリアント」と言ったりします。 variantは(変形・別形)という意味です。 valiantという(勇敢な)という綴りが違う英単語がありますが、綴りに「r」が入っている方の単語の意味です。
おまけその2-どの書式にも合致しない引数を付与した場合-
オーバーロード関数を呼び出した際、どの多重定義にも合致しない引数を付与した場合、「no one of the overloads can be applied to the function call(呼び出しに対して、どの多重定義も適用てきません)」というコンパイルエラーが発生します。↓
動画のサンプルコードでは、3つの書式を定義しています。
引数なしのパターン
引数が1つのパターン
引数が2つのパターン
動画途中で、引数を3つ設定して再コンパイルしたところで、エラーが発生しているのがわかるかと思います。
-おまけその3-:オーバーロードとオーバーライド
同じ名前の関数に複数の機能を持たせるという意味では、「関数のオーバーライド」という概念もあります。
ただ、オーバーライドについてはこの後
MQL5 EA講座 第53回「クラスについて6 -仮想関数-」
の中にて解説を行っていきますので、今は意味については理解しなくても大丈夫です。
まとめ
今回の記事では以下のことを学びました
今回は以上になります。
最後までお読みいただきありがとうございました<m(__)m>
※まだ先の内容にはなりますが、講座記事
第97回「トレーリングストップクラスを作る2」では今回解説したオーバーロード関数の仕組みを利用した内容となっています。
コメント