关于如何在C ++中为函数参数赋予默认值,我有一个小问题。我遇到的问题可能是由于我对函数原型或函数头中声明/定义参数的位置缺乏了解,或者两者兼而有之?代码如下,并注明错误:
#include <iostream>
using namespace std;
float volume(float l, float w, float h);
int main() {
float length;
float width;
float height;
cout << volume() << endl; // Here, with 'volume()' underlined, it says:
//no matching function for call to 'volume()'
cout << "Length: ";
cin >> length;
cout << "Width: ";
cin >> width;
cout << "Height: ";
cin >> height;
cout << "Volume = " << volume(length, width, height) << endl;
}
float volume(float l = 1, float w = 1, float h = 1){
float vol = l * w * h;
return vol;
}
在另一次尝试中,发生了什么:
#include <iostream>
using namespace std;
float volume(float l = 1, float w = 1, float h = 1);
int main() {
float length;
float width;
float height;
cout << volume() << endl;
cout << "Length: ";
cin >> length;
cout << "Width: ";
cin >> width;
cout << "Height: ";
cin >> height;
cout << "Volume = " << volume(length, width, height) << endl;
}
float volume(float l = 1, float w = 1, float h = 1){ //Here, Xcode says that
// that the error is: Redefinition of default argument. < which I believe I understand.
float vol = l * w * h;
return vol;
}
在我的最后一次尝试中,这是有效的,我这样做了:
#include <iostream>
using namespace std;
float volume(float l = 1, float w = 1, float h = 1);
int main() {
float length;
float width;
float height;
cout << volume() << endl;
cout << "Length: ";
cin >> length;
cout << "Width: ";
cin >> width;
cout << "Height: ";
cin >> height;
cout << "Volume = " << volume(length, width, height) << endl;
}
float volume(float l, float w, float h){
float vol = l * w * h;
return vol;
}
有人可以向我解释为什么后者工作的逻辑,而前两个没有?是否有另一种方式,代码仍然可以使用其他地方指定的参数以及在其他地方设置的默认值以相同的方式工作?这个领域是否有任何惯例或更有利的做法?
亚当
答案 0 :(得分:1)
C ++和C自上而下解析。当编译器解释一个语句时,它还不知道它还没有读过的东西。
在你的第一个例子中,你声明了一个名为&#34; volume&#34;的函数,原型为3个浮点数并返回一个浮点数。然后尝试调用一个名为&#34; volume&#34;的函数。没有参数,它还没有存在(它将是一个不同的函数,因为C ++支持多态)。您稍后定义了一个可以使用0,1,2或3个浮点数的函数,但它太晚了并且与第一个浮点数具有不兼容的原型。
你的第二个例子直觉上是错误的,有点像定义变量两次,但是当默认值相同时,我没有任何关于无效代码的具体信息。
必须在函数原型中指定默认参数,必须在首次使用之前进行,以便编译器了解它。通常,您可以将原型的默认值放在头文件中,该头文件包含在代码上方。
在处理共享头文件中的默认参数时要注意的一件事,特别是如果将其与动态库一起使用时:参数的默认值与调用者一起存储,而不是被调用的函数。也就是说,如果使用新的默认值更新函数并且不重建调用该函数的代码,则调用代码仍将使用旧的默认值。
答案 1 :(得分:0)
从 Bjarne Stroustrup
添加上述答案默认参数在函数声明时进行类型检查,并在调用时进行评估。可以仅为尾随参数提供默认参数。例如:
int f(int,int = 0,char * = 0); //好的
int g(int = 0,int = 0,char *); //错误
int h(int = 0,int,char * = 0); //错误
默认参数可以在同一范围内的后续声明中重复,但不能更改。 例如:
void f(int x = 7);
void f(int = 7); //好的
void f(int = 8); //错误:不同的默认参数
void g(){void f(int x = 9); // ok:这个声明隐藏了外部的一个}
在嵌套作用域中声明名称,以便名称在外部作用域中隐藏同名声明,这很容易出错。
答案 2 :(得分:0)
默认值可以在函数声明中定义,就像您在第三次尝试中所做的那样。这意味着它们通常出现在头文件中,尽管这不是一个规则。
请注意,函数声明是作用域的。这意味着只要函数具有不同的范围,您就可以拥有多个函数声明:
void f(int);
int main() {
f(3); // argument should specified.
void f(int = 1);
f(); // calls f(1)
}
void f(int n = 2) {
}
void g() {
f(); // calls f(2)
}
在第二次尝试中,您将默认值放在函数的声明和定义上。这会导致编译器混淆,因为它们处于相同的范围内。