オーバーロードとは日本語で「多重定義」と呼ばれる考え方です。
C言語では、同じ機能を持つ関数でも全く同じ関数名を付ける事は出来ませんでした。
例えば、絶対値を求める「abs」という関数があります。
C言語でのサンプルを書いてみます。
<sample program cpp009-01>
#include <stdio.h> #include <stdlib.h> int main() { int value; value = 5; printf("value = %d\n", abs(value)); value = -5; printf("value = %d\n", abs(value)); return 0; } |
<実行結果>
value = 5 value = 5 続行するには何かキーを押してください・・・
正しく絶対値を求めています。
では、値を実数(小数)に変えたらどうなるでしょうか?
<sample program cpp009-02>
#include <stdio.h> #include <stdlib.h> int main() { double value; value = 5; printf("value = %f\n", abs(value)); value = -5; printf("value = %f\n", abs(value)); return 0; } |
<コンパイル結果>
error C2668: 'abs': オーバーロード関数の呼び出しを解決することができません。(新機能 ; ヘルプを参照) note: '__int64 abs(const __int64) throw()' の可能性があります note: または 'long abs(const long) throw()' note: または 'int abs(int)' note: 引数リスト '(double)' を一致させようとしているとき error C2668: 'abs': オーバーロード関数の呼び出しを解決することができません。(新機能 ; ヘルプを参照) note: '__int64 abs(const __int64) throw()' の可能性があります note: または 'long abs(const long) throw()' note: または 'int abs(int)' note: 引数リスト '(double)' を一致させようとしているとき warning C4473: 'printf': 書式文字列として渡された引数が不足しています note: プレースホルダーとそのパラメーターには 1 の可変個引数が必要ですが、0 が指定されています。 note: 不足している可変個引数 1 が書式文字列 '%f' に必要です warning C4473: 'printf': 書式文字列として渡された引数が不足しています note: プレースホルダーとそのパラメーターには 1 の可変個引数が必要ですが、0 が指定されています。 note: 不足している可変個引数 1 が書式文字列 '%f' に必要です
何かいっぱい出ました・・・
要は「absは整数用なので、実数は渡せないよ!」という事です。
実数用の絶対値は「math.h」をインクルードする事で使える「fabs」という関数を使う事で求められます。
<sample program cpp009-03>
#include <stdio.h> #include <math.h> int main() { double value; value = 5; printf("value = %f\n", fabs(value)); value = -5; printf("value = %f\n", fabs(value)); return 0; } |
<実行結果>
value = 5.000000 value = 5.000000 続行するには何かキーを押してください・・・
やりたい事は「絶対値を求める」という事ですが、型が異なると別関数を呼ばなければなりません。
同じ機能を持った関数なのに、何個も関数名を覚えなければならないのも面倒です。
そこで、オーバーロードの出番です。
関数のオーバーロードとは、同じ名前の関数を複数作ることが出来るという事です。
ただし「引数の数や型が異ならなければならない」という制限があります。
1つ例を書きます。
<sample program cpp009-04>
#include <iostream> int Twice(const int value); int main() { std::cout << Twice(12) << std::endl; return 0; } int Twice(const int value) { return value * 2; } |
<実行結果>
24 続行するには何かキーを押してください・・・
単純に受け取った値を2倍する関数です。
プログラムはそのままで、渡している12を実数に変えてみます。
<sample program cpp009-05>
#include <iostream> int Twice(const int value); int main() { std::cout << Twice(12.5) << std::endl; return 0; } int Twice(const int value) { return value * 2; } |
<実行結果>
24 続行するには何かキーを押してください・・・
コンパイル時に警告が出ています。
warning C4244: '引数': 'double' から 'const int' への変換です。データが失われる可能性があります。
引数を受け取る変数valueは「const int型」ですから、小数以下の数値は切り捨てられます。
そのため、結果は24となっています。
では、このTwice関数をオーバーロード(多重定義)します。
<sample program cpp009-06>
#include <iostream> int Twice(const int value); double Twice(const double value); int main() { std::cout << Twice(12.5) << std::endl; return 0; } int Twice(const int value) { return value * 2; } double Twice(const double value) { return value * 2; } |
<実行結果>
25 続行するには何かキーを押してください・・・
警告も無くなり、結果も25になりました。
Twiceという名前の関数が2つありますが、引数が「const int」と「const double」で異なっています。
引数として渡す値が「整数」であれば、引数が「const int」のTwice関数が呼び出されます。
引数として渡す値が「実数」であれば、引数が「const double」のTwice関数が呼び出されます。
引数の型によって、呼び出す関数を選んでいるのです。
そのため、引数で区別が付かない関数を作った場合はエラーになります。
<sample program cpp009-07>
#include <iostream> int Twice(const int value); int Twice(int value); int main() { std::cout << Twice(12) << std::endl; return 0; } int Twice(const int value) { return value * 2; } int Twice(int value) { return value * 2; } |
<コンパイル結果>
error C2084: 関数 'int Twice(const int)' は既に本体を持っています。
このTwiceは引数が「const int」と「int」で異なっているように見えます。
が、12を渡して呼び出すとした場合に、どちらを呼び出せば良いか区別が付きません。
次の関数があったとします。
void Func(int value); |
この関数のオーバーロードとして正しいかどうか問題を出します。
1.int Func(int value); 2.void Func(int x); 3.void Func(int a, int b); 4.int Func(double value); 5.void Func(); |
考えてみてください。
解答です。
×1.int Func(int value); ×2.void Func(int x); ○3.void Func(int a, int b); ○4.int Func(double value); ○5.void Func(); |
まず、戻り値は判断材料になりませんので、見る必要はありません。
あくまでも「引数の数と型」です。
×1.int Func(int value); 戻り値はintになっていますが、引数は同じint型です。 |
×2.void Func(int x); これも引数の変数名は異なりますが、型は同じです。 |
○3.void Func(int a, int b); これは引数の数が異なりますから大丈夫です。 |
○4.int Func(double value); これも引数の型が異なるのでOKです。 |
○5.void Func(); これも引数の数が異なります。 |
関数のオーバーロードを使う際には、上記の事に気を付けてください。
また、C++にはテンプレートという考え方があり、それを使う事で楽にオーバーロードさせることが出来ます。
※テンプレートは2つ後で説明します。