多重定義
[Wikipedia|▼Menu]
.mw-parser-output .hatnote{margin:0.5em 0;padding:3px 2em;background-color:transparent;border-bottom:1px solid #a2a9b1;font-size:90%}

「オーバーローディング」はプログラミング言語の仕組みについて説明しているこの項目へ転送されています。その他の用法については「オーバーロード」をご覧ください。

多重定義 (たじゅうていぎ) あるいは オーバーロード (: overload) とは、プログラミング言語において同一の名前(シンボル)を持つ関数あるいはメソッドおよび同一の演算子記号について複数定義し、利用時にプログラムの文脈に応じて選択することで複数の動作を行わせる仕組みである。 例えば整数型浮動小数点型複素数型の値について同じ「abs」という関数を定義して絶対値を求める、ごとに個々の意味で名前やIDを返す関数を定義するなどが挙げられる。多重定義する対象に応じてそれぞれ関数の多重定義[注釈 1]、演算子の多重定義[注釈 2]、メソッドの多重定義[注釈 3]と呼ばれる。メソッドの多重定義の特殊なケースとして、コンストラクタの多重定義がある。また、Common Lispなどでは、多重定義可能な関数としてgeneric function(en:Generic function)がある(このgenericはジェネリックプログラミングのジェネリックである)。

動作の「上書き」を意味するオーバーライド[注釈 4]とはまったく異なる概念である。オーバーライドは動的なポリモーフィズム(多態)に利用される。
概要

動作を選択する際に用いられる代表的な文脈情報としては、型付けられたプログラミング言語においては関数や演算子に実引数(演算子ならばオペランド)として与えられた式や変数に関連付けられたの情報が用いられる(稀ではあるが戻り値を利用できるプログラミング言語も存在する)。関数の名称とそれらの型情報の組を合わせたものをシグネチャと呼ぶが、プログラム内でシグネチャが唯一に決まれば、関数名やメソッド名、演算子の記号が重複していても呼び出すべき対象を唯一に決定することができる。このような型付けによる多重定義は、暗黙の型変換[注釈 5]あるいは型強制[注釈 6])、継承[注釈 7]あるいは包含[注釈 8]総称型[注釈 9]、あるいはパラメーター付型[注釈 10]と並んでプログラミング言語において多態性[注釈 11]を実現するための一つの手段である。

理論的には関数の名前や演算子記号は単なる記号であり、意味的必然があるわけではないので、これを反映して多重定義を許すプログラミング言語では多重定義された関数や演算子、メソッドの意味や動作の定義はかなり自由に行うことができる(演算子については構文解析の都合上、優先順位などが制限される場合も有る)。とはいえ関数名やメソッド、特に演算子の用法には各分野及びプログラミング言語毎に慣習が育っている場合があり、著名な関数(例えば数学関数のsinなど)やメソッド、演算子に対して慣習とあまりにかけ離れた意味、即ち動作の定義を与えるとプログラムの可読性の著しい低下をもたらす可能性があるので注意が必要である。

デフォルト引数(オプション引数)をサポートしない言語(Javaや、バージョン4.0よりも前のC#など)では、多重定義によってデフォルト引数と類似の機能を実現することができる。
言語による多重定義のサポート

関数の多重定義をサポートしない言語では、たとえ関数の引数の型や数によらずアルゴリズムすなわち本質的な内容がまったく同じでも、引数の型や数ごとに関数をそれぞれ定義する場合は同じ名前が使えず、引数に応じた名前をそれぞれ付ける必要があり、呼び出すときも引数に応じて使い分ける必要がある。

C言語での例を以下に示す。#include <stdio.h>#include <math.h>float vector2f_length(float x, float y) { return sqrtf(x * x + y * y); }double vector2d_length(double x, double y) { return sqrt(x * x + y * y); }float vector3f_length(float x, float y, float z) { return sqrtf(x * x + y * y + z * z); }double vector3d_length(double x, double y, float z) { return sqrt(x * x + y * y + z * z); }int main(void){ printf("%f\n", vector2f_length(1.0f, -1.0f)); printf("%f\n", vector2d_length(1.0, 2.0)); printf("%f\n", vector3f_length(1.0f, -1.0f, 1.0f)); printf("%f\n", vector3d_length(1.0, 2.0, -1.0));}

ベクトルの長さを計算する関数を、型および次元ごとに命名している。

一方、関数の多重定義をサポートする言語では、関数のシグネチャが異なれば同じ名前を使うことができる。関数には本質的な名前だけを付ければよく、呼び出すときも引数によらず一様に記述できる。

C++での例を以下に示す。#include <cstdio>#include <cmath>float vector_length(float x, float y) { return std::sqrt(x * x + y * y); }double vector_length(double x, double y) { return std::sqrt(x * x + y * y); }float vector_length(float x, float y, float z) { return std::sqrt(x * x + y * y + z * z); }double vector_length(double x, double y, float z) { return std::sqrt(x * x + y * y + z * z); }int main(void){ printf("%f\n", vector_length(1.0f, -1.0f)); // (float, float) バージョンが呼ばれる。 printf("%f\n", vector_length(1.0, 2.0)); // (double, double) バージョンが呼ばれる。 printf("%f\n", vector_length(1.0f, -1.0f, 1.0f)); // (float, float, float) バージョンが呼ばれる。 printf("%f\n", vector_length(1.0, 2.0, -1.0)); // (double, double, double) バージョンが呼ばれる。}

なお、C++11規格では、2次元ベクトルの長さを求める標準関数として、多重定義されたstd::hypot()関数が用意されている[1]C++17では3次元ベクトルバージョンも追加されている。
ルックアップ

多重定義のルックアップ(: look-up、探索)は実引数の型に応じて静的に解決される。以下のJavaの例では、java.lang.Stringクラスはjava.lang.Objectクラスから派生しているものの、testMethod()は引数の動的な型情報(実行時型情報)によって選択されることはなく、あくまでコンパイル時に解決される静的な型情報に基づいて選択される。


次ページ
記事の検索
おまかせリスト
▼オプションを表示
ブックマーク登録
mixiチェック!
Twitterに投稿
オプション/リンク一覧
話題のニュース
列車運行情報
暇つぶしWikipedia

Size:28 KB
出典: フリー百科事典『ウィキペディア(Wikipedia)
担当:undef