У меня есть небольшой вопрос о том, как значения по умолчанию задаются для параметров функции в 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;
}
Может ли кто-нибудь объяснить мне логику, почему последний работал, а первые два — нет? Есть ли другой способ, которым код все еще будет работать таким же образом с параметрами, указанными в другом месте, или значениями по умолчанию, установленными в другом месте? Существуют ли какие-либо соглашения или более предпочтительные практики в этой области?
Адам
C ++ и C анализируются сверху вниз. Когда компилятор интерпретирует утверждение, он не знает о вещах, которые еще не прочитал.
В вашем первом примере вы объявляете функцию с именем «volume», которая в качестве прототипа принимает 3 float и возвращает float. Затем вы пытаетесь вызвать функцию с именем «volume», которая не принимает параметров, которых еще нет (это будет другая функция, поскольку C ++ поддерживает полиморфизм). Позже вы определяете функцию, которая может принимать 0, 1, 2 или 3 числа с плавающей запятой, но это слишком поздно и имеет несовместимый прототип с первым.
Ваш второй пример интуитивно имеет смысл ошибаться, вроде как определение переменных дважды, но у меня нет никакой конкретной информации о том, почему это недопустимый код, когда значения по умолчанию идентичны.
Параметры по умолчанию должны быть указаны в прототипе функции, что должно произойти до первого использования, чтобы компилятор знал об этом. Как правило, вы помещаете прототипы со значениями по умолчанию в заголовочный файл, который добавляется над кодом.
Одна вещь, на которую следует обратить внимание при работе с параметрами по умолчанию из общего заголовочного файла, особенно если вы используете его с динамическими библиотеками: значения по умолчанию для параметров хранятся в вызывающей программе, а не в вызываемой функции. То есть, если вы обновите функцию новыми значениями по умолчанию и не пересобираете код, вызывающий эту функцию, старые значения по-прежнему будут использоваться вызывающим кодом.
Добавление к ответу выше от Бьярне Страуструп
Аргумент по умолчанию — это тип, проверяемый во время объявления функции и оцениваемый во время вызова. Аргументы по умолчанию могут быть предоставлены только для конечных аргументов. Например:
int f (int, int = 0, char * = 0); // Хорошо
int g (int = 0, int = 0, char *); // ошибка
int h (int = 0, int, char * = 0); // ошибка
Аргумент по умолчанию может быть повторен в последующем объявлении в той же области, но не изменен.
Например:
пустота f (int x = 7);
пустота f (int = 7); // Хорошо
пустота f (int = 8); // ошибка: разные аргументы по умолчанию
void g () {void f (int x = 9); // хорошо: это объявление скрывает внешнее}
Объявление имени во вложенной области видимости так, что имя скрывает объявление с тем же именем во внешней области, подвержено ошибкам.
Значения по умолчанию мог быть определенным в объявлении функции, как вы сделали в своей третьей попытке. Это означает, что обычно они появляются в заголовочных файлах, хотя это не правило.
Обратите внимание, что объявления функций ограничены. Это означает, что вы можете иметь более одного объявления для функции, если они имеют разные области действия:
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)
}
Во второй попытке вы помещаете значения по умолчанию как в объявление, так и в определение функции. Это приводит к путанице компилятора, потому что они находятся в той же области видимости.