void func(int n, float b = 1.2, char c = '@') {
cout << n << ", " << b << ", " << c << endl;
}
int main() {
func(10, 3.5, '#'); // 10, 3.5, #
func(20, 9.8); // 20, 9.8, @ (c 使用預設值)
func(30); // 30, 1.2, @ (b, c 皆用預設值)
return 0;
}
// ✅ 合法
void f1(int a, int b = 10, int c = 20);
void f2(int a, int b, int c = 20);
// ❌ 非法:預設參數後出現無預設參數
void f3(int a, int b = 10, int c = 20, int d);
void f4(int a, int b = 10, int c, int d = 20);
原因:實參從左至右依序匹配,中間有「洞」編譯器無法判斷意圖。
float base = 10.8;
void func(int n, float b = base + 2.9, char c = '@'); // 合法,執行期求值
// MyLib.h
void foo(int a, int b = 10); // 宣告處給預設值
// MyLib.cpp
#include "MyLib.h"
void foo(int a, int b) { // 定義處「不寫」預設值
// ...
}
這確保同一翻譯單元內只有一處預設值,避免一致性問題。
// 無預設參數:需 3 個重載
void drawRect(int x, int y);
void drawRect(int x, int y, int w);
void drawRect(int x, int y, int w, int h);
// 有預設參數:1 個函數涵蓋所有
void drawRect(int x = 0, int y = 0, int w = 100, int h = 100);
| 陷阱 | 現象 | 對策 |
|---|---|---|
| 虛擬函數預設參數 | 靜態綁定:基類指標呼叫派生類虛擬函數,使用**基類宣告的預設值** | 虛擬函數避免使用預設參數,或基類派生類保持一致 |
| 預設參數修改需重編譯所有呼叫端 | 頭文件改預設值 → 所有包含該頭文件的 .cpp 需重編譯 | 預設值相對穩定時使用;頻繁變動改用重載 |
| 預設參數為暫時物件 | void f(const string& s = string("")) 每次呼叫建構臨時物件 | 改用 const char* 或 C++17 string_view |
type name = value。