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)
{
}
Обидва працюють; який стандартний спосіб і чому ?
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)
{
}
Обидва працюють; який стандартний спосіб і чому ?
Відповіді:
Якщо ви помістите декларацію у файл заголовка, а визначення - в окремий .cpp
файл, а #include
заголовок - з іншого .cpp
файлу, ви зможете побачити різницю.
Припустимо:
int Add(int a, int b);
int Add(int a, int b = 3) {
...
}
#include "lib.h"
int main() {
Add(4);
}
Компіляція test.cpp
не побачить декларацію параметрів за замовчуванням і не вдасться із помилкою.
З цієї причини визначення параметра за замовчуванням зазвичай задається у декларації функції :
int Add(int a, int b = 3);
b
визначається один раз для кожного .cpp
файлу, що включає заголовок. Але це нормально, тому що у вас є лише одне оголошення Add
функції.
У C ++ вимоги, що пред'являються до аргументів за замовчуванням щодо їх розташування в списку параметрів, є такими:
Аргумент за замовчуванням для даного параметра повинен бути вказаний не більше одного разу. Вказувати його не раз (навіть із тим самим значенням за замовчуванням) є незаконним.
Параметри з аргументами за замовчуванням повинні утворювати суміжну групу в кінці списку параметрів.
Тепер, маючи це на увазі, в 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)
роботи це потрібно оголосити після void foo(int a, int b = 5)
. Так, це спрацює. І ні, це не синтаксична помилка. g ++ 4.5.3 складе це ідеально добре.
int foo(int)
. Я вважаю, що можу писати int foo(int=5)
ще раз, не залишаючи імен параметрів. Здається, ніхто ще не згадував про це.
Перший спосіб віддав перевагу другому.
Це відбувається тому, що файл заголовка покаже, що параметр є необов’язковим і яким буде його значення за замовчуванням. Крім того, це забезпечить, що значення за замовчуванням буде однаковим, незалежно від реалізації відповідного .cpp-файлу.
По-друге, немає гарантії значення за замовчуванням для другого параметра. Значення за замовчуванням може змінюватися залежно від способу реалізації відповідного .cpp-файлу.
b
буде визначено кілька разів, один раз для кожної одиниці компіляції, що включаєlib.h
, це правильно?