【问题标题】:Default value of function parameter函数参数的默认值
【发布时间】:2011-02-20 00:55:41
【问题描述】:

1.

int Add (int a, int b = 3);
int Add (int a, int b)
{

}

2.

int Add (int a, int b);
int Add (int a, int b = 3)
{

}

两者都有效;这是标准方式,为什么

【问题讨论】:

    标签: c++ syntax optional-parameters


    【解决方案1】:

    如果您将声明放在头文件中,将定义放在单独的 .cpp 文件中,而 #include 头文件来自不同的 .cpp 文件,您将能够看到差异。

    具体来说,假设:

    lib.h

    int Add(int a, int b);
    

    lib.cpp

    int Add(int a, int b = 3) {
       ...
    }
    

    test.cpp

    #include "lib.h"
    
    int main() {
        Add(4);
    }
    

    test.cpp的编译不会看到默认的参数声明,会失败并报错。

    为此,通常在函数声明中指定默认参数定义:

    lib.h

    int Add(int a, int b = 3);
    

    【讨论】:

    • 那么b会被定义多次,每个编译单元包含lib.h一次,对吗?
    • @httpinterpret:在某种意义上是的,b 的默认值是为包含标题的 每个 .cpp 文件定义一次。但这没关系,因为您只有一个 Add 函数声明。
    • @httpinterpret 编译器会在生成调用者代码时通过默认参数添加未指定的参数。这就是为什么默认值必须在函数原型中而不是在函数实现中的原因。该参数在变量定义的意义上没有定义,因为原型没有定义变量。
    • 这个答案可以编辑,因为快速解析(只看代码,直到“出于这个原因”)让我理解了你的意思。
    【解决方案2】:

    必须在函数名的第一次出现时指定默认参数——通常在函数原型中。如果因为函数定义也用作原型而省略了函数原型,则应在函数头中指定默认参数。

    【讨论】:

      【解决方案3】:

      第一种方式比第二种方式更受欢迎。

      这是因为头文件会显示参数是可选的以及它的默认值是什么。此外,这将确保默认值相同,无论对应的 .cpp 文件的实现如何。

      在第二种方式中,不能保证第二个参数的默认值。默认值可能会发生变化,具体取决于相应 .cpp 文件的实现方式。

      【讨论】:

        【解决方案4】:

        在 C++ 中,对于默认参数在参数列表中的位置的要求如下:

        1. 必须指定给定参数的默认参数不超过一次。多次指定它(即使使用相同的默认值)是非法的。

        2. 具有默认参数的参数必须在参数列表的末尾形成一个连续的组。

        现在,请记住这一点,在 C++ 中,只要持续满足上述要求,就可以将具有默认参数的参数集从函数的一个声明“增长”到下一个。

        例如,你可以声明一个没有默认参数的函数

        void foo(int a, int b);
        

        为了在声明后调用该函数,您必须明确指定两个参数。

        稍后(进一步向下)在同一个翻译单元中,您可以再次重新声明它,但这次使用一个默认参数

        void foo(int a, int b = 5);
        

        从现在开始,您可以只使用一个显式参数来调用它。

        再往下你可以重新声明它,再添加一个默认参数

        void foo(int a = 1, int b);
        

        从现在开始,您可以在没有显式参数的情况下调用它。

        完整示例如下所示

        void foo(int a, int b);
        
        int main()
        {
          foo(2, 3);
        
          void foo(int a, int b = 5); // redeclare
          foo(8); // OK, calls `foo(8, 5)`
        
          void foo(int a = 1, int b); // redeclare again
          foo(); // OK, calls `foo(1, 5)`
        }
        
        void foo(int a, int b)
        {
          // ...
        }
        

        至于您问题中的代码,这两种变体都是完全有效的,但它们的含义不同。第一个变体立即为第二个参数声明一个默认参数。第二个变体最初声明你的函数没有默认参数,然后为第二个参数添加一个。

        两个声明的最终效果(即第二个声明之后的代码所看到的方式)完全相同:函数的第二个参数具有默认参数。但是,如果您设法在第一个和第二个声明之间压缩一些代码,这两个变体的行为将有所不同。在第二个变体中,函数在声明之间没有默认参数,因此您必须明确指定两个参数。

        【讨论】:

        • 我不认为你定义的代码 void foo(int a = 1, int b) 会工作。您需要在一个可选参数之后拥有所有可选参数。这是一个语法错误(至少在我的系统上使用 g++ 4.5.3)。
        • @Nilesh:正如我在上面明确说过的(这就是这个例子的重点),void foo(int a = 1, int b) 必须在 after void foo(int a, int b = 5) 之后才能工作。是的,它会起作用。不,这不是语法错误。 g++ 4.5.3 可以完美编译。
        • 好的,所以函数从前面的声明中获取 b 的值。现在拿到东西。谢谢:-)
        • @Nilesh:是的,默认参数声明是在翻译单元中的所有先前声明中累积的。
        • 我喜欢编写不带变量名的函数原型,例如int foo(int)。我发现我可以再次写int foo(int=5),省略参数名称。似乎还没有人提到这一点。
        【解决方案5】:

        这里要记住的是,默认参数必须是函数定义中的最后一个参数。

        以下代码将无法编译:

        void fun(int first, int second = 10, int third);
        

        以下代码将编译:

        void fun(int first, int second, int third = 10);
        

        【讨论】:

          猜你喜欢
          • 2011-04-09
          • 2010-11-28
          • 1970-01-01
          • 2019-09-11
          • 2012-08-03
          • 2015-07-08
          • 2011-08-26
          • 1970-01-01
          相关资源
          最近更新 更多