関数オーバーロード
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 57/104。
関数オーバーロードを使用すると、同じ名前で異なるパラメータリストを持つ複数の関数を定義できます。コンパイラは、渡された引数に基づいて適切なバージョンを選択します。これは、コンパイル時ポリモーフィズムの主要な形式です。
オーバーロードを機能させるには、関数はそのシグネチャ(引数の数、型、またはその両方)が異なっている必要があります:
class Calculator {
public:
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
};
Calculator calc;
calc.add(5, 3); // add(int, int) を呼び出します
calc.add(2.5, 3.7); // add(double, double) を呼び出します
calc.add(1, 2, 3); // add(int, int, int) を呼び出しますコンパイラは各呼び出しを検証し、適切なオーバーロードに一致させます。これは完全にコンパイル時に行われるため、ランタイムオーバーヘッドは発生しません。
重要: 戻り値の型だけでは、オーバーロードされた関数を区別することはできません。以下はコンパイルエラーを引き起こします:
int getValue();
double getValue(); // エラー: 戻り値の型のみでオーバーロードすることはできません関数オーバーロードにより、コードがより直感的になります。addInts、addDoubles、addThreeInts のような個別の名前を作成する代わりに、1つの意味のある名前を使用し、残りの処理はコンパイラに任せることができます。
チャレンジ
簡単関数のオーバーロードの威力を示すメッセージフォーマッタクラスを作成しましょう。複数の format() メソッドを持つ Formatter クラスを作成します。これらのメソッドは異なるタイプの入力を処理し、渡された引数に基づいてコンパイラが適切なバージョンを選択します。
コードは2つのファイルに分けて構成します:
Formatter.h: 異なるシナリオを処理する、オーバーロードされたformat()メソッドを持つFormatterクラスを定義します:- 1つの
std::stringを受け取り、次のように出力するメソッド:Message: <text> std::stringとint型の優先度レベルを受け取り、次のように出力するメソッド:[Priority <priority>] <text>std::stringとdouble型のタイムスタンプを受け取り、次のように出力するメソッド:[<timestamp>s] <text>- 3つの
std::stringパラメータ(送信者、受信者、メッセージ)を受け取り、次のように出力するメソッド:From <sender> to <receiver>: <message>
format()とする必要があります。コンパイラは引数に基づいて正しいメソッドを選択します。- 1つの
main.cpp: 4つの入力(それぞれ別の行)を読み取ります:- シンプルなメッセージテキスト
- 優先度レベル(整数)
- タイムスタンプ(浮動小数点数)
- 送信者名
Formatterオブジェクトを作成し、4つのオーバーロードされたメソッドすべてを実演します:- メッセージテキストのみを指定して
format()を呼び出す - メッセージテキストと優先度を指定して
format()を呼び出す - メッセージテキストとタイムスタンプを指定して
format()を呼び出す - 送信者、受信者として "Admin"、およびメッセージテキストを指定して
format()を呼び出す
例えば、入力が System ready、3、12.5、Server の場合:
Message: System ready
[Priority 3] System ready
[12.5s] System ready
From Server to Admin: System ready同じメソッド名 format() を4回呼び出していますが、引数の型や数に基づいて、各呼び出しが異なるバージョンを呼び出していることに注目してください。これがコンパイル時ポリモーフィズムの動作です。コンパイラは、プログラムが実行される前に、どのオーバーロードを使用するかを決定します。
チートシート
関数オーバーロードを使用すると、同じ名前でパラメータリストが異なる複数の関数を定義できます。コンパイラは、コンパイル時に渡された引数に基づいて正しいバージョンを選択します。
関数は、そのシグネチャ(パラメータの数、型、またはその両方)が異なっている必要があります:
class Calculator {
public:
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
};
Calculator calc;
calc.add(5, 3); // add(int, int) を呼び出します
calc.add(2.5, 3.7); // add(double, double) を呼び出します
calc.add(1, 2, 3); // add(int, int, int) を呼び出します重要: 戻り値の型だけでは、オーバーロードされた関数を区別することはできません:
int getValue();
double getValue(); // エラー: 戻り値の型のみでオーバーロードすることはできません関数オーバーロードは、実行時のオーバーヘッドがないコンパイル時ポリモーフィズムの一形態です。
自分で試してみよう
#include <iostream>
#include <string>
#include "Formatter.h"
using namespace std;
int main() {
// 入力を読み込む
string message;
getline(cin, message);
int priority;
cin >> priority;
double timestamp;
cin >> timestamp;
cin.ignore();
string sender;
getline(cin, sender);
// TODO: Formatter オブジェクトを作成する
// TODO: メッセージテキストのみを指定して format() を呼び出す
// TODO: メッセージテキストと priority を指定して format() を呼び出す
// TODO: メッセージテキストと timestamp を指定して format() を呼び出す
// TODO: sender、受信者として "Admin"、およびメッセージテキストを指定して format() を呼び出す
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス