404 Not Found

404 Not Found


nginx

関数のオーバーロード

もし、異なる型に対応する関数が必要になった場合はどうすればよいでしょうか? addIntaddDoubleaddFloat と記述することもできますが、それは面倒です。関数のオーバーロードを使えば、複数の関数に同じ名前を付けることができ、コンパイラが引数に基づいて適切な関数を選択してくれます。


1. 関数のオーバーロードとは何か?

関数のオーバーロードとは、同じ名前でありながら、異なる引数リスト(引数の数や型が異なる)を持つ複数の関数を定義することを指します。

CPP
int add(int a, int b) {
 return a + b;
}

double add(double a, double b) {
 return a + b;
}

int main() {
 std::cout << add(3, 5) << std::endl; // Calls int version
 std::cout << add(3.14, 2.86) << std::endl; // Calls double version
 return 0;
}

コンパイラは、渡された引数に基づいて適切な関数を選択します。

💡 重要なポイント: オーバーロードはコンパイル時に決定されます。これはコンパイル時多態性(または静的バインディング)と呼ばれます。コンパイラは引数の型を確認し、最も適合するものを選択します。



2. オーバーロードのルール

(1) 2.1 パラメータ数の違い

CPP
void print(int a) { ... }
void print(int a, int b) { ... }
void print(int a, int b, int c) { ... }

(2) 2.2 パラメータの種類

CPP
void print(int a) { ... }
void print(double a) { ... }
void print(std::string a) { ... }

(3) 2.3 対象外となるもの

以下の方法ではオーバーロードすることはできません:

CPP
// ❌ These are NOT overloads — same signature
int foo(int a);
double foo(int a); // Error: already defined
💡 ヒント: 関数のシグネチャとは、その名前とパラメータの型のことである。戻り値の型はシグネチャには含まれない。



3. オーバーロードの解決

オーバーロードされた関数を呼び出すと、コンパイラは以下の手順を実行します。

  1. 完全一致 — 引数の型と完全に一致する関数を検索します
  2. プロモーション — 数字によるプロモーションを試みます(例:intdouble
  3. 変換 — 標準的な変換を試みます(例:intlong
  4. ユーザー定義の変換 — コンストラクタまたは変換演算子を試す

(1) ▶ サンプル:コンパイラがどのように判断するか

CPP
#include iostream

void print(int x) {
 std::cout << "Integer: " << x << std::endl;
}

void print(double x) {
 std::cout << "Double: " << x << std::endl;
}

int main() {
 print(42); // Exact match → int version
 print(3.14); // Exact match → double version
 print('A'); // char can promote to int → int version
 return 0;
}
▶ 試してみよう

4. デフォルト引数を用いたオーバーロード

注意してください。オーバーロードとデフォルト引数を組み合わせると、曖昧さが生じる可能性があります。

CPP
// ❌ Ambiguous call
void func(int a) { ... }
void func(int a, int b = 10) { ... }

int main() {
 func(5); // ❌ Both functions match! Compiler error
 return 0;
}
💡 ヒント: デフォルト引数を使用する場合、通常はオーバーロードは必要ありません。デフォルト引数を持つ1つの関数の方が、複数のオーバーロードされたバージョンよりもコードがすっきりします。



5. 実践例

▶ サンプル 1: オーバーロードされた Max 関数 (難易度 ⭐⭐)

CPP
#include iostream

int max(int a, int b) {
 return (a > b) ? a : b;
}

double max(double a, double b) {
 return (a > b) ? a : b;
}

int max(int a, int b, int c) {
 return max(max(a, b), c);
}

int main() {
 std::cout << "max(3, 7): " << max(3, 7) << std::endl;
 std::cout << "max(3.14, 2.86): " << max(3.14, 2.86) << std::endl;
 std::cout << "max(3, 7, 5): " << max(3, 7, 5) << std::endl;
 return 0;
}
▶ 試してみよう

▶ サンプル 2: オーバーロードされた表示関数 (難易度 ⭐⭐)

CPP
#include iostream
#include string
#include vector

void display(int value) {
 std::cout << "Integer: " << value << std::endl;
}

void display(double value) {
 std::cout << "Double: " << value << std::endl;
}

void display(const std::string& value) {
 std::cout << "String: " << value << std::endl;
}

void display(const std::vectorint& values) {
 std::cout << "Vector: [";
 for (size_t i = 0; i < values.size(); i++) {
 std::cout << values[i];
 if (i < values.size() - 1) std::cout << ", ";
 }
 std::cout << "]" << std::endl;
}

int main() {
 display(42);
 display(3.14);
 display("Hello C++");
 display({1, 2, 3, 4, 5});
 return 0;
}
▶ 試してみよう

6. 演算子のオーバーロード(プレビュー)

C++ では、独自の型に対して +-<< などの演算子をオーバーロードすることもできます。これは関数のオーバーロードと密接に関連しています。

CPP
// Preview: overloading the << operator for a custom struct
struct Point {
 int x, y;
};

std::ostream& operator<<(std::ostream& os, const Point& p) {
 os << "(" << p.x << ", " << p.y << ")";
 return os;
}

演算子のオーバーロードについては、後で詳しく説明します。とりあえず、ここでも同じオーバーロードの仕組みが適用されることを覚えておいてください。


❓ よくある質問

Q 戻り値の型だけで関数をオーバーロードすることはできますか?
A いいえ。コンパイラは、戻り値ではなく引数に基づいて、どの関数を呼び出すかを決定する必要があります。名前と引数が同じで、戻り値の型が異なる2つの関数があると、コンパイルエラーが発生します。
Q コンパイラはどのオーバーロードを呼び出すかをどのように決定するのですか?
A 以下の優先順位に従います:①完全一致、②型昇格(char → int、float → double)、③標準変換(int → double)、④ユーザー定義の変換。2つのオーバーロードが同等に適している場合、曖昧さエラーが発生します。
Q 異なるネームスペースで関数をオーバーロードすることはできますか?
A はい、各ネームスペースには独自のスコープがあります。A::foo()B::foo() を定義することができます。これらは異なる関数であり、同じ関数のオーバーロードではありません。
Q 一致するオーバーロードがない場合はどうなりますか?
A コンパイラは「一致する関数が見つかりません」というエラーを出します。通常、エラーメッセージには利用可能なオーバーロードが一覧表示されるため、何が問題だったのかを確認できます。

📖 まとめ


📝 練習問題

  1. 初心者(難易度 ⭐): print のオーバーロード関数を 3 つ作成してください。1 つは int 用、1 つは double 用、もう 1 つは std::string 用です。それぞれ、型と値を表示するようにしてください。

  2. 中級(難易度 ⭐⭐): 2つのオーバーロードされた average 関数を記述してください。1つは2つの double パラメータを取り、もう1つは3つのパラメータを取ります。これらをテストしてください。

  3. 上級(難易度 ⭐⭐⭐): オーバーロードされた convert 関数をいくつか作成してください。1つは摂氏を華氏に変換し、もう1つは華氏を摂氏に変換するものです。両方の変換を実演してください。



7. 🚀 次は

次に、スコープと有効期間(第14課)について学びます。変数がどこに存在し、どのくらいの期間存続するのかを理解します。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%