Standardwert des Funktionsparameters

130

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)
{

}

Beide arbeiten; Welches ist der Standardweg und warum ?

httpinterpret
quelle

Antworten:

203

Wenn Sie die Deklaration in eine Header-Datei und die Definition in eine separate .cppDatei und #includeden Header aus einer anderen .cppDatei einfügen, können Sie den Unterschied erkennen.

Nehmen wir insbesondere an:

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);
}

Bei der Kompilierung von test.cppwird die Standardparameterdeklaration nicht angezeigt und ein Fehler schlägt fehl.

Aus diesem Grund wird die Standardparameterdefinition normalerweise in der Funktionsdeklaration angegeben :

lib.h.

int Add(int a, int b = 3);
Greg Hewgill
quelle
Dann bmehrfach definiert werden, einmal für jede Übersetzungseinheit , die beinhaltet lib.h, ist das richtig?
httpinterpret
@httpinterpret: In gewisser Hinsicht ja, der Standardwert von bwird einmal für jede .cpp Datei definiert, die den Header enthält. Aber das ist okay, weil Sie nur eine Deklaration der AddFunktion haben.
Greg Hewgill
1
@httpinterpret Der Compiler fügt den nicht angegebenen Parameter als Standardparameter hinzu, wenn der Aufrufercode generiert wird. Aus diesem Grund MUSS der Standardwert im Funktionsprototyp und nicht in der Funktionsimplementierung enthalten sein. Der Parameter wird nicht definiert im Sinne der Variablendefinition , da der Prototyp - Variablen nicht definiert.
Harper
1
Diese Antwort konnte bearbeitet werden, da ich durch schnelles Parsen (nur den Code betrachten und erst "Aus diesem Grund") das Gegenteil von dem verstand, was Sie meinten.
Gabriel Devillers
44

In C ++ lauten die Anforderungen an Standardargumente hinsichtlich ihrer Position in der Parameterliste wie folgt:

  1. Das Standardargument für einen bestimmten Parameter darf nicht mehr als einmal angegeben werden. Die mehrmalige Angabe (auch bei gleichem Standardwert) ist unzulässig.

  2. Parameter mit Standardargumenten müssen am Ende der Parameterliste eine zusammenhängende Gruppe bilden.

Unter Berücksichtigung dessen können Sie in C ++ den Parametersatz "erweitern", der Standardargumente von einer Deklaration der Funktion zur nächsten enthält, solange die oben genannten Anforderungen kontinuierlich erfüllt werden.

Sie können beispielsweise eine Funktion ohne Standardargumente deklarieren

void foo(int a, int b);

Um diese Funktion nach einer solchen Deklaration aufzurufen, müssen Sie beide Argumente explizit angeben.

Später (weiter unten) in derselben Übersetzungseinheit können Sie sie erneut deklarieren, diesmal jedoch mit einem Standardargument

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

und von diesem Punkt an können Sie es mit nur einem expliziten Argument aufrufen.

Weiter unten können Sie es erneut deklarieren und ein weiteres Standardargument hinzufügen

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

und von diesem Punkt an können Sie es ohne explizite Argumente aufrufen.

Das vollständige Beispiel könnte wie folgt aussehen

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)
{
  // ...
}

Was den Code in Ihrer Frage betrifft, sind beide Varianten vollkommen gültig, aber sie bedeuten unterschiedliche Dinge. Die erste Variante deklariert sofort ein Standardargument für den zweiten Parameter. Die zweite Variante deklariert Ihre Funktion zunächst ohne Standardargumente und fügt dann eines für den zweiten Parameter hinzu.

Der Nettoeffekt Ihrer beiden Deklarationen (dh wie er im Code nach der zweiten Deklaration angezeigt wird) ist genau der gleiche: Die Funktion verfügt über ein Standardargument für ihren zweiten Parameter. Wenn Sie es jedoch schaffen, Code zwischen der ersten und der zweiten Deklaration zusammenzudrücken, verhalten sich diese beiden Varianten unterschiedlich. In der zweiten Variante hat die Funktion keine Standardargumente zwischen den Deklarationen, daher müssen Sie beide Argumente explizit angeben.

Ameise
quelle
Ich denke nicht, dass Ihr Code definiert void foo (int a = 1, int b) funktionieren würde. Sie müssen alle optionalen Parameter nach einem optionalen Parameter haben. Es ist ein Syntaxfehler (zumindest mit g ++ 4.5.3 auf meinem System).
Nilesh
@Nilesh: Wie ich ausdrücklich gesagt oben (und das ist der springende Punkt dieses Beispiels) für void foo(int a = 1, int b)sie arbeiten muss erklärt werden nach void foo(int a, int b = 5) . Ja, es wird funktionieren. Und nein, es ist kein Syntaxfehler. g ++ 4.5.3 wird es perfekt kompilieren.
Am
Okay, die Funktion nimmt den Wert von b aus der vorherigen Deklaration an. Jetzt das Ding bekommen. Danke :-)
Nilesh
1
@Nilesh: Ja, die Standardargumentdeklarationen werden in allen vorherigen Deklarationen in der Übersetzungseinheit gesammelt.
ANT
1
Ich schreibe gerne meine Funktionsprototypen ohne Variablennamen, wie int foo(int). Ich finde, dass ich int foo(int=5)wieder schreiben kann , ohne die Parameternamen. Bisher scheint das noch niemand erwähnt zu haben.
Victor Eijkhout
5

Der erste Weg wäre dem zweiten vorzuziehen.

Dies liegt daran, dass in der Header-Datei angezeigt wird, dass der Parameter optional ist und der Standardwert lautet. Dadurch wird außerdem sichergestellt, dass der Standardwert unabhängig von der Implementierung der entsprechenden CPP-Datei gleich ist.

Zweitens gibt es keine Garantie für einen Standardwert für den zweiten Parameter. Der Standardwert kann sich ändern, je nachdem, wie die entsprechende CPP-Datei implementiert ist.

user342264
quelle
4

Standardargumente müssen beim ersten Auftreten des Funktionsnamens angegeben werden - normalerweise im Funktionsprototyp. Wenn der Funktionsprototyp weggelassen wird, weil die Funktionsdefinition auch als Prototyp dient, sollten die Standardargumente im Funktionsheader angegeben werden.

Clyfe
quelle