ProgrammingC++エンジニア

C++におけるクラスメンバー関数のオーバーロードとデフォルト引数の動作を説明してください。オーバーロードされた関数とデフォルト引数の使用における微妙さは何ですか?

Hintsage AIアシスタントで面接を突破

答え。

関数のオーバーロード(overloading)とは、同じ名前の関数を異なるシグネチャ(パラメータの数や型)を持つ複数の関数として宣言するメカニズムです。

デフォルト引数は、関数の宣言時に指定できます。微妙さ:デフォルト引数は呼び出しのコンパイル時にのみ考慮され、コンパイラは見えるシグネチャに基づいてそれを置き換えます。

クラスでは次のような状況が頻繁に見られます:

class Printer { void print(int n, char c = '*') { /* ... */ } void print(const std::string& s) { /* ... */ } }; Printer p; p.print(5); // print(int n, char c = '*')が呼び出され、cは'*' p.print("Hi"); // print(const std::string&)が呼び出される

微妙さ:

  • 関数を同時にオーバーロードし、デフォルト引数だけで区別するのは避けるべきです。これは曖昧さを引き起こします。
void foo(int x, int y = 10); void foo(int x); foo(1); // エラー:どの関数を呼び出すか不明

トリックのある質問。

クラスメンバー関数のデフォルト引数を指定できる唯一の場所はどこですか?

答え:クラスメソッドのデフォルト引数は、クラス内のメソッド宣言(またはクラスの外部での最初の宣言)で指定することが許可されているが、クラス内部と実装の両方で指定することは許可されていません。そうしないと再定義のエラーが発生します。

class X { void func(int x = 5); // ここで可能 }; void X::func(int x) { /* ... */ } // しかしここではダメ!

このトピックの微妙さを知らないことによる実際のエラーの例。


物語 1

銀行ソフトウェアでは、コンパイル時にエラーが発生しました:異なるデフォルト引数を持つオーバーロードされた関数が必要なものの明確な選択を妨げ、コンパイル時に呼び出しが曖昧になり、手動修正を行うまでリリースをビルドできないという結果になりました。


物語 2

チームには、すべてのデフォルト引数を実装に置くスタイルが広まりましたが、クラスの一部のメソッドに対しては、インターフェースと実装の間で不一致を引き起こし、異なるTUが異なる関数パラメータを見て、奇妙なコンパイル時およびランタイムバグを引き起こしました。


物語 3

公共ライブラリを拡張する際に、同じパラメータを持つ関数のオーバーロードが異なるデフォルト引数で誤って追加されました。コンパイラはAPI呼び出しの曖昧さを報告し、ユーザーは古い呼び出しや壊れたバイナリ互換性に直面しました。