デフォルト引数
関数呼び出しを柔軟に。引数を省略可能にする方法
概要
デフォルト引数により、 関数の引数にデフォルト値を設定できます。
呼び出し側で引数を省略した場合、 デフォルト値が使われます。
これにより、関数の呼び出しが より柔軟で使いやすくなります。
基本形
戻り値の型 関数名(型 引数1 = デフォルト値1, 型 引数2 = デフォルト値2) {
// 処理
}
例
#include <iostream>
void greet(std::string name = "Guest") {
std::cout << "こんにちは, " << name << "!" << std::endl;
}
int main() {
greet(); // "こんにちは, Guest!"
greet("太郎"); // "こんにちは, 太郎!"
return 0;
}
こんにちは, Guest!
こんにちは, 太郎!
name引数は省略可能。
省略された場合、"Guest" が使われます。
複数のデフォルト引数
例:矩形の描画
#include <iostream>
void drawRectangle(int width, int height, char border = '*') {
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
std::cout << border;
}
std::cout << std::endl;
}
}
int main() {
drawRectangle(5, 3); // *で描画
std::cout << std::endl;
drawRectangle(5, 3, '#'); // #で描画
return 0;
}
*****
*****
*****
#####
#####
#####
重要なルール
ルール1: デフォルト引数は右から順に
デフォルト値を持つ引数は、 左側のすべてがデフォルト値を持つ必要はありません。 しかし、実務では右側に集めるのが慣例です。
// 良い例
void func(int a, int b = 10, int c = 20) { }
// 悪い例(避けるべき)
void func(int a = 5, int b, int c) { } // エラー
ルール2: 宣言と定義での指定
デフォルト値は宣言(プロトタイプ)時に指定します。 定義時に重複して指定するとエラーです。
// 正しい
int add(int a, int b = 0); // 宣言時にデフォルト値を指定
int add(int a, int b) { // 定義時には指定しない
return a + b;
}
// 誤り
int multiply(int a, int b = 1); // 宣言
int multiply(int a, int b = 1) { // エラー!: 重複
return a * b;
}
実践例
例1: ファイル出力関数
#include <iostream>
void writeLine(const std::string & text, int times = 1, char separator = '\n') {
for (int i = 0; i < times; i++) {
std::cout << text;
if (i < times - 1) {
std::cout << separator;
}
}
std::cout << std::endl;
}
int main() {
writeLine("Hello"); // 1回出力
writeLine("World", 3); // 3回、改行区切り
writeLine("Test", 4, ' '); // 4回、スペース区切り
return 0;
}
Hello
World
World
World
Test Test Test Test
例2: 支払い計算機
#include <iostream>
#include <iomanip>
double calculateTotal(double price, int quantity = 1, double taxRate = 0.1) {
return price * quantity * (1.0 + taxRate);
}
int main() {
std::cout << std::fixed << std::setprecision(2);
std::cout << "単価100円、1個: " << calculateTotal(100) << std::endl;
std::cout << "単価100円、3個: " << calculateTotal(100, 3) << std::endl;
std::cout << "単価100円、3個、税率0: " << calculateTotal(100, 3, 0.0) << std::endl;
return 0;
}
単価100円、1個: 110.00
単価100円、3個: 330.00
単価100円、3個、税率0: 300.00
オーバーロード vs デフォルト引数
同じことがオーバーロードでもできますが、 デフォルト引数の方がシンプルな場合が多いです。
比較
// デフォルト引数を使った方法
void display(int x = 0, int y = 0) {
std::cout << "(" << x << ", " << y << ")" << std::endl;
}
// オーバーロードを使った方法
void display() {
display(0, 0);
}
void display(int x) {
display(x, 0);
}
void display(int x, int y) {
std::cout << "(" << x << ", " << y << ")" << std::endl;
}
デフォルト引数を使った方がよりシンプルですね。 ただし、処理が大きく異なる場合はオーバーロードが適切です。
デフォルト値の注意点
例:デフォルト値は関数呼び出し時に評価
#include <iostream>
int getValue() {
static int counter = 0;
return ++counter;
}
void display(int x = getValue()) {
std::cout << x << std::endl;
}
int main() {
display(); // getValue() が呼ばれて 1
display(); // getValue() が呼ばれて 2
display(10); // getValue() は呼ばれない(明示的に10を渡す)
return 0;
}
1
2
10
ポイント
- デフォルト引数で関数呼び出しを柔軟に
- デフォルト値は宣言時に指定
- デフォルト引数は右側に集める
- オーバーロードと組み合わせて使うことも可能
- デフォルト値の評価は呼び出し時
よくある誤り
誤り1: デフォルト引数を左側に置く
void func(int a = 10, int b) { } // エラー!
// 呼び出す時に func(5) とした場合、
// 5 が a に行くのか b に行くのか不明確
誤り2: 定義時にもデフォルト値を指定
void func(int x = 5); // 宣言
void func(int x = 5) { // エラー!: 重複
// ...
}
誤り3: 避けるべき使い方
// グローバル変数をデフォルト値として使う(避けるべき)
int globalValue = 0;
void process(int x = globalValue) {
std::cout << x << std::endl;
}
やってみよう
練習1: 計算機関数に適切なデフォルト値を追加。
練習2: 出力フォーマット関数(フォーマット、幅、精度のデフォルト)。
練習3: ユーザー認証関数(デフォルト役割は"user")。
チャレンジ: クラスのメンバー関数にデフォルト引数を追加。
まとめ
- デフォルト引数で関数呼び出しを簡潔に
- 宣言時に指定し、定義時に重複させない
- デフォルト引数 vs オーバーロード:状況に応じて選択
- 関数のインターフェース設計に重要な要素