4.1. 输入和输出
1. 返回值的倾向性:
- 倾向于使用按值返回,而不是按引用返回。
- 避免返回指针,除非指针可以为空。
2. 参数和返回值的使用:
- C++函数通过返回值提供输出,有时也通过参数提供输出。
- 倾向于使用返回值提高可读性,通常提供相同或更好的性能。
3. 参数类型:
- 非可选输入参数通常使用值参或`const`引用。
- 非可选输出参数或输入/输出参数通常使用引用(不能为空)。
- 可选参数使用`std::optional`表示按值输入,使用`const`指针表示其他输入,非常量指针表示输出和输入/输出参数。
4. const引用参数的生命周期问题:
- 避免定义函数,其需要`const`引用参数超出其生命周期,因为`const`引用不能绑定到临时变量。
- 应消除生命周期要求或通过`const`指针传递,并记录生命周期和非空要求。
5. 参数排序:
- 在排序函数参数时,将所有输入参数放在所有输出参数之前。
- 新增参数时,应按照规则排序,即使它们是新参数,也应将输入参数置于输出参数之前。
6. 规则的灵活性:
- 这不是硬性规定,输入/输出参数可能使问题复杂化。
- 有时为了与其他函数保持一致,可能需要变通。
4.2. 编写简短函数
长函数有时是合理的, 因此并不硬性限制函数的长度. 如果函数超过 40 行, 可以思索一下能不能在不影响程序结构的前提下对其进行分割。
4.3. 函数重载
1. 函数重载的定义:
- 可以编写参数类型不同的同名函数,例如一个接受`const string&`,另一个接受`const char*`。
2. 函数重载的使用原则:
- 调用点应该清晰,使读者能够立即识别调用的是哪一个重载版本,包括构造函数。
3. 函数重载的优点:
- 通过参数类型不同的重载,可以使代码更直观。
- 模板化代码需要重载,这为使用者带来便利。
4. 函数重载的缺点:
- 如果函数仅通过不同的参数类型进行重载,读者需要熟悉C++的匹配规则来理解匹配过程。
- 如果派生类只重载了基类函数的某些变体,可能会引起继承语义上的困惑。
5. 结论和建议
- 如果打算重载函数,考虑在函数名中加入参数信息,如`AppendString()`和`AppendInt()`,而不是重载多个`Append()`。
- 如果重载函数的目的是为了支持不同数量的同一类型参数,优先考虑使用`std::vector`,允许使用者通过列表初始化指定参数。
4.4. 缺省参数
1. 缺省参数的使用原则:
缺省参数是指在定义函数时给某个参数设置一个默认值,当函数被调用时,如果没有传递该参数,就会使用默认值。
- 只允许在非虚函数中使用缺省参数。
- 必须保证缺省参数的值始终一致。
2. 缺省参数与函数重载:
- 遵循与函数重载相同的规则。
- 一般情况下建议使用函数重载。
3. 缺省参数的优点:
- 提供了便利,允许在大多数情况下使用默认参数,偶尔使用非默认参数。
- 语法更简洁明了,减少样板代码,区分“必要参数”和“可选参数”。
4. 缺省参数的缺点:
- 与函数重载一样,存在不应使用的理由。
- 虚函数调用时,缺省参数取决于静态类型,可能无法保证所有重载声明相同的缺省参数。
- 每次调用时都可能有不同的取值,导致代码膨胀。
- 会干扰函数指针,导致签名不一致。
5. 结论:
- 虚函数不允许使用缺省参数,因为可能无法正常工作。
- 如果每个调用点缺省参数的值可能不同,也不允许使用缺省函数。
- 在其他情况下,如果缺省参数对可读性的提升超过了缺点,可以使用。
- 如果有疑惑,优先使用函数重载。
4.5. 函数返回类型后置语法
1. 返回类型后置语法的使用原则:
- 仅在常规写法(返回类型前置)不便书写或不便阅读时使用返回类型后置语法。
2. 定义:
- C++允许两种函数声明方式:
1)传统的返回类型前置
int foo(int x);
2)C++11引入的返回类型后置
后置返回类型使用`auto`关键字,并在参数列表后指定返回类型。
auto foo(int x) -> int;
3. 优点:
- 后置返回类型是指定Lambda表达式返回值的唯一方式。
- 显式指定返回类型可以提高代码的可读性。
- 在返回类型依赖于模板参数时,后置语法可能简化书写并提高易读性。
4. 缺点:
- 后置返回类型是较新的语法,可能对读者来说比较陌生。
- 在已有代码中,混用新旧语法可能导致不规整。
5. 结论:
- 大部分情况下,应继续使用传统的返回类型前置写法。
- 只在必需时(如Lambda表达式)或后置语法能显著简化书写和提高易读性时使用后置语法。
- 复杂模板代码中的后置语法使用应谨慎,因为大多数情况下不鼓励编写过于复杂的模板代码。