为什么要默认参数在C ++函数最后加入?为什么要默认参数在C ++函数最后加入?(Why shoul

2019-06-14 08:22发布

为什么要默认参数在C ++函数最后加入?

Answer 1:

为了简化语言定义并保持代码的可读性。

void foo(int x = 2, int y);

要调用,并采取默认值的优势,你需要的语法是这样的:

foo(, 3);

这可能是觉得太不可思议。 另一种方法是在参数列表中指定的名称:

foo(y : 3);

一个新的符号必须使用,因为这已经意味着什么:

foo(y = 3); // assign 3 to y and then pass y to foo.

命名方法被认为是因为他们与引入函数定义以外的参数名称的新的意义不舒服通过ISO委员会否决。

如果您想了解更多C ++的设计基本原理,阅读的设计与++的C进化由斯特劳斯。



Answer 2:

如果定义了以下功能:

void foo( int a, int b = 0, int c );

你将如何调用该函数以及A和C提供一个值,但留下B作为默认?

foo( 10, ??, 5 );

与其他一些语言(例如,Python)的,函数参数在C / C ++不能通过名称限定,如下所示:

foo( a = 10, c = 5 );

如果这是可能的,那么默认的参数可以在列表中的任何地方。



Answer 3:

想象一下,你有没有和这台样机的功能:

void testFunction(bool a = false, bool b = true, bool c);

现在假设我这样调用该函数:

testFunction(true, false);

编译器应该如何找出哪些参数我的意思是供应值?



Answer 4:

由于大部分的答案指出,有参数列表可能随时随地默认参数增加的函数调用的复杂性和不确定性(编译器和可能更重要的是为功能的用户两者)。

关于C ++的一个好处是,有经常的方式做你想做的(即使它并不总是一个好主意)。 如果你想有默认参数的各种参数的位置,你可以几乎肯定写重载简单地转身,并呼吁全参数化功能内嵌做到这一点:

 int foo( int x, int y);
 int foo( int y) {
     return foo( 0, y);
 }

有你有相当于:

 int foo( int x = 0, int y);


Answer 5:

作为一般规则,功能参数由编译器处理和在右放置在堆栈上到左的顺序。 因此,它是有道理的,使用默认值的任何参数,应首先评估。

(这applieds到__cdecl,这往往是为VC ++和__stdcall函数声明的默认值)。



Answer 6:

它的,因为它使用的参数的相对位置,以找到他们所对应的参数。

它可能使用的类型,以确定一个可选的参数并没有给出。 但是,隐式转换可能会干扰它。 作为可选参数退出,而不是失踪的说法错误的另一个问题将得到编程可以解释的错误。

为了让任何参数成为可选的,应该有一个方法来确定的参数,以确保没有任何编程错误或删除歧义。 这可能是在某些语言,但不是在C ++。



Answer 7:

该标准委员会不得不考虑的另一件事情是默认参数如何与其他功能,如重载函数,模板分辨率和名称查找交互。 这些特性的交互非常复杂,很难形容已经途径。 制作默认参数可以在任何地方出现只会增加复杂性。



Answer 8:

这是一个关于调用约定的事情。 电话会议:当你调用一个函数,参数是在压入堆栈从右到左。 例如

fun(int a, int b, int c);

栈是这样的:A B C所以,如果你设置从左至右这样的默认值:

fun(int a = 1, int b = 2, int c);

并调用是这样的:

fun(4,5);

您的呼叫装置设定的= 4,B = 5,和c =无值; //这是错误的!

如果你声明的功能是这样的:

fun(int a, int b = 2, int c = 3);

并调用这样的: fun(4, 5);

您的呼叫装置设定的= 4,B = 5,和c =默认值(3); // 哪个是对的!

总之,你应该从右到左把默认值。



Answer 9:

曾静是正确的。 我想在这里补充我的话。 当一个函数被调用,参数从右到左压入堆栈。 例如,假设你有这样的任意函数。

int add(int a, int b) {
  int c;
  c = a + b;
  return c;
}

下面是该函数的堆栈帧:

------
  b
------
  a
------
 ret
------
  c
------

上面这个图是该功能的堆栈帧! 正如你所看到的,第一个B被压入堆栈,然后被压入堆栈。 在此之后,函数返回地址被压入堆栈。 该函数返回地址拥有其中函数原名主的位置(),函数执行完毕后,程序的执行转到该函数的返回地址。 然后任何局部变量如c被压入堆栈。

现在关键的是,参数被压入堆栈从右到左。 基本上被提供的任何默认参数是文字值,它们被存储在一个可执行的代码段。 当程序执行遇到默认参数没有相应的参数,它推动该文字值压入堆栈的顶部。 然后,它着眼于和推动参数的值压入堆栈的顶部。 堆栈指针总是指向堆栈的顶部,您最近推变量。 所以你压入堆栈的任何文字值作为默认参数是“幕后黑手”堆栈指针。

这可能是更高效的编译器能够快速推动第一任意默认文字值到堆栈中第一个,因为他们没有存储在存储器中的位置,并迅速建立堆栈。 想想本来如果变量会被压入堆栈,然后再在文字。 访问CPU的存储器位置占用相比拉动文字值出来的电路或CPU寄存器的相对长的时间。 因为它需要更多的时间来推动变量到堆栈与文字,字面值将不得不等待,然后返回地址将不得不等待,局部变量将不得不等待为好。 这可能不是效率的大问题,但是这只是我为什么默认参数总是在C中的函数头++的最右边的位置理论。 这意味着,编译器就是如此设计的。



文章来源: Why should default parameters be added last in C++ functions?