代码仓库shanchuann/CPP-Learninng

缺省参数

核心定义

缺省参数是指函数在声明或定义时,为参数指定一个 “默认值”。调用函数时,若未显式传递该参数,编译器会自动使用默认值;若传递了参数,则覆盖默认值。其核心作用是减少函数重载的冗余代码,同时提升调用灵活性(尤其适用于 “可选参数” 场景)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <string>
// 函数声明时指定缺省参数(推荐:声明更易被调用者可见)
void printMsg(int count = 1, const std::string& msg = "Hello");

// 函数定义时不可重复指定默认值(否则编译错误)
void printMsg(int count, const std::string& msg) {
for (int i = 0; i < count; ++i) {
std::cout << msg << std::endl;
}
}

// 调用方式(三种均合法)
int main() {
printMsg(); // 未传参:count=1,msg="Hello"
printMsg(3); // 传1个参:count=3,msg="Hello"
printMsg(2, "Hi"); // 传2个参:覆盖默认值
return 0;
}

缺省参数的关键规则

缺省参数的使用有严格限制,违反会导致编译错误,需重点注意以下 5 点:

右到左指定原则

缺省参数必须从最右侧参数开始连续指定,不能跳过左侧参数给右侧参数设默认值。这是因为函数调用时参数按 “左到右” 传递,若左侧有默认值而右侧无,编译器无法判断省略的是哪个参数。

  • 合法示例:void func(int a, int b = 5, int c = 10);(从右到左设默认)
  • 非法示例:void func(int a = 1, int b, int c = 3);(左侧 a 有默认,中间 b 无,违反顺序)

单处指定”原则

缺省参数只能在函数声明或定义中选择一处指定,不能两处重复定义(否则编译器无法确定默认值)。实际开发中推荐在 “声明” 中指定(如头文件.h 中),因为声明是调用者可见的接口,定义(.cpp 中)可能隐藏在实现文件中。

  • 非法示例:

    1
    2
    3
    4
    // 头文件声明(已指定默认值)
    void func(int a = 0);
    // 源文件定义(重复指定,编译错误)
    void func(int a = 1) {}

常量性要求

缺省参数的默认值必须是编译期可确定的常量表达式,或全局 / 静态变量(局部变量不可用,因局部变量生命周期与函数调用无关,可能被销毁)。

  • 合法示例:

    1
    2
    3
    const int GLOBAL_NUM = 10;
    void func1(int a = 5 + 3); // 常量表达式
    void func2(int a = GLOBAL_NUM); // 全局变量
  • 非法示例:

    1
    2
    3
    4
    5
    void outer() {
    int local = 5;
    // 局部变量作为默认值,编译错误
    void inner(int a = local) {}
    }

与函数重载

文档 “语言” 部分明确提到 “函数 − 重载”,而缺省参数若使用不当,会与重载函数产生二义性(编译器无法判断调用哪个函数),需特别规避。

  • 二义性示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 重载函数1:无参数
    void func() { std::cout << "func()" << std::endl; }
    // 重载函数2:单参数带默认值
    void func(int a = 0) { std::cout << "func(int)" << std::endl; }

    int main() {
    func(); // 编译错误:无法判断调用func()还是func(0)
    return 0;
    }

类成员函数特殊限制

若缺省参数用于类的非静态成员函数,默认值不能直接访问类的非静态成员变量(因非静态成员属于对象实例,函数调用时可能未构造对象,无法确定成员值)。

  • 非法示例:

    1
    2
    3
    4
    5
    6
    7
    class A {
    private:
    int x = 5;
    public:
    // 非静态成员x作为默认值,编译错误
    void func(int a = x) {}
    };

缺省参数的典型应用场景

结合文档中 “容器库”“字符串库” 等标准库设计思路,缺省参数在实际开发中常见于以下场景:

简化构造函数重载

避免为 “可选成员变量” 编写多个重载构造函数,用缺省参数直接指定默认值(如标准库std::string的构造:std::string(size_t n = 0, char c = '\0'))。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Person {
private:
std::string name;
int age;
public:
// 单构造函数覆盖多种初始化场景,替代3个重载构造函数
Person(std::string n = "Unknown", int a = 0) : name(n), age(a) {}
};

// 调用方式
Person p1; // name="Unknown", age=0
Person p2("Alice"); // name="Alice", age=0
Person p3("Bob", 25); // name="Bob", age=25

可选配置参数

函数的 “非必需配置项” 用缺省参数指定默认行为(如日志函数的 “日志级别” 默认设为 “INFO”,文件读取函数的 “编码格式” 默认设为 “UTF-8”)。

1
2
3
4
5
6
7
8
9
10
enum class LogLevel { INFO, WARN, ERROR };
// 日志函数:level默认INFO,filename默认"app.log"
void log(const std::string& content,
LogLevel level = LogLevel::INFO,
const std::string& filename = "app.log") {
// 实现日志写入逻辑
}

// 调用:仅传递必需的content,其他用默认
log("Program started");