C++では、関数の引数にあらかじめ既定の値(デフォルト値)を設定することができる仕組みがあります。
これを「デフォルト引数」と呼びます。
この仕組みを使うと、関数を呼び出すときにすべての引数を指定しなくてもよくなり、一部の引数を省略して関数を呼び出すことができます。
つまり、関数の設計者が「この引数は通常この値になることが多い」という値をあらかじめ設定しておくことで、呼び出し側のコードを簡潔にできます。
この仕組みは、C++のライブラリ設計やAPI設計で非常によく利用されており、関数の使いやすさ(インターフェース設計)を改善する重要な機能です。
デフォルト引数の基本的な仕組み
デフォルト引数を持つ関数では、引数を省略して関数を呼び出した場合、省略された引数にはあらかじめ指定された値が自動的に使われます。
重要な点として、デフォルト引数は実行時に決定されるわけではありません。
C++では、デフォルト引数は
- 関数内部で補われる
- 実行時に計算される
という仕組みではなく、
関数を呼び出す側のコンパイル時に補われる
という仕様になっています。
つまり、コンパイラが関数呼び出しを解析する段階で、不足している引数を既定値で補完して解釈します。
省略できる引数のルール
C++のデフォルト引数には重要なルールがあります。
省略できる引数は、必ず右端(最後)から連続していなければならないというルールです。
これは関数呼び出しの曖昧さを防ぐためです。
もし途中の引数だけを省略できるようにすると、呼び出し時に「どの引数が省略されたのか」を判断できなくなってしまいます。
そのため、C++ではこのような仕様になっています。
つまり、関数の設計では
- 必須の引数は左側に置く
- 省略可能な引数は右側に置く
という設計にする必要があります。
デフォルト引数と関数宣言の関係
C++では、デフォルト引数は通常関数の宣言部分(ヘッダ)に記述するのが一般的です。
これは、関数を呼び出す側がコンパイル時にデフォルト値を参照するためです。
もしデフォルト引数を関数の定義側だけに書いてしまうと、呼び出し側のコンパイル時にその情報が見えない可能性があります。そのため、多くの場合はヘッダファイルに記述されます。
また、同じ引数に対してデフォルト値を二重に指定することはできません。
ただし、後からの宣言で、まだデフォルト値が設定されていない引数に対して追加される形でデフォルト値が指定されることはあります。
関数オーバーロードとの関係
C++では、同じ名前で異なる引数の関数を定義する「関数オーバーロード」という仕組みがあります。
デフォルト引数は、このオーバーロードの代わりとして使われることがあります。
たとえば
- 引数が1つの関数
- 引数が2つの関数
をそれぞれ用意する代わりに、2つ目の引数にデフォルト値を設定することで、1つの関数で両方の呼び出しに対応できます。
しかし、オーバーロードとデフォルト引数を組み合わせると、どの関数を呼び出すべきか曖昧になる場合があります。
そのような場合、C++ではコンパイルエラーになります。
そのため、ライブラリ設計では
- デフォルト引数
- 関数オーバーロード
の両方を使う場合は、呼び出しが曖昧にならないよう注意が必要です。
クラスのメンバ関数でも使用できる
デフォルト引数は、通常の関数だけでなく、クラスのメンバ関数でも使用できます。
オブジェクト指向設計においては、クラスのメソッドにデフォルト引数を設定することで、呼び出し側のコードを簡潔にすることができます。
ただし、仮想関数とデフォルト引数を組み合わせる場合には注意が必要です。
C++では、仮想関数の呼び出し先は実行時に決まりますが、デフォルト引数はコンパイル時に決まります。
このため、仮想関数を通じて呼び出した場合でも、使用されるデフォルト引数は呼び出し側の静的型に基づいて決定されるという特徴があります。
この仕様はC++特有のものであり、設計を誤ると意図しない動作を引き起こす可能性があります。
デフォルト引数がよく使われる理由
デフォルト引数は、主に次のような目的で使われます。
1. 関数の使いやすさを向上させるため
多くの場合、関数のすべての引数を毎回指定する必要はありません。
よく使われる値をデフォルト値として設定しておくことで、呼び出しを簡潔にできます。
2. APIの柔軟性を高めるため
関数の設計者は、利用者が必要に応じて詳細なパラメータを指定できるようにしつつ、通常はシンプルに呼び出せるインターフェースを提供できます。
3. オーバーロードの数を減らすため
似たような関数を複数定義する代わりに、デフォルト引数を使うことで関数数を減らすことができます。
まとめ
C++のデフォルト引数の重要ポイントを整理すると次のようになります。
- 引数に既定値を設定することで、関数呼び出し時に引数を省略できる
- 省略できるのは右端から連続する引数のみ
- デフォルト値は呼び出し側のコンパイル時に補われる
- 同じ引数に対してデフォルト値を二重に指定することはできない
- 関数オーバーロードと組み合わせると曖昧呼び出しが起こる場合がある
- クラスのメンバ関数でも利用できる
- 仮想関数と組み合わせると特殊な挙動になるため注意が必要
以上、C++の引数の省略についてでした。
最後までお読みいただき、ありがとうございました。
