Valore predefinito del parametro della funzione


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

}

Entrambi funzionano; qual è il modo standard e perché ?

Risposte:


203

Se inserisci la dichiarazione in un file di intestazione e la definizione in un .cppfile separato e #includel'intestazione di un .cppfile diverso , sarai in grado di vedere la differenza.

In particolare, supponiamo:

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

La compilazione di test.cppnon vedrà la dichiarazione del parametro predefinito e non riuscirà con un errore.

Per questo motivo, la definizione del parametro predefinito è generalmente specificata nella dichiarazione della funzione :

lib.h

int Add(int a, int b = 3);

Quindi bverrà definito più volte, una volta per ogni unità di compilazione che include lib.h, giusto?
httpinterpret

@httpinterpret: in un certo senso sì, il valore predefinito di bviene definito una volta per ogni .cpp file che include l'intestazione. Ma va bene, perché hai una sola dichiarazione della Addfunzione.
Greg Hewgill,

1
@httpinterpret Il compilatore aggiungerà il parametro non specificato dal parametro predefinito quando viene generato il codice chiamante. Ecco perché il valore predefinito DEVE essere nel prototipo della funzione e non nell'implementazione della funzione. Il parametro non è definito nel senso della definizione della variabile poiché il prototipo non definisce le variabili.
Harper,

1
Questa risposta potrebbe essere modificata perché una rapida analisi (solo guardando il codice e non andando fino a "Per questo motivo") mi ha fatto capire il contrario di ciò che intendevi.
Gabriel Devillers,

44

In C ++ i requisiti imposti agli argomenti predefiniti per quanto riguarda la loro posizione nell'elenco dei parametri sono i seguenti:

  1. L'argomento predefinito per un determinato parametro non deve essere specificato più di una volta. Specificarlo più di una volta (anche con lo stesso valore predefinito) è illegale.

  2. I parametri con argomenti predefiniti devono formare un gruppo contiguo alla fine dell'elenco dei parametri.

Ora, tenendo presente ciò, in C ++ è possibile "far crescere" l'insieme di parametri che hanno argomenti predefiniti da una dichiarazione della funzione alla successiva, purché i requisiti di cui sopra siano costantemente soddisfatti.

Ad esempio, è possibile dichiarare una funzione senza argomenti predefiniti

void foo(int a, int b);

Per chiamare quella funzione dopo tale dichiarazione dovrai specificare esplicitamente entrambi gli argomenti.

Più tardi (più in basso) nella stessa unità di traduzione, è possibile dichiararlo nuovamente, ma questa volta con un argomento predefinito

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

e da questo punto in poi puoi chiamarlo con un solo argomento esplicito.

Più in basso è possibile dichiararlo nuovamente aggiungendo un altro argomento predefinito

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

e da questo punto in poi puoi chiamarlo senza argomenti espliciti.

L'esempio completo potrebbe apparire come segue

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

Per quanto riguarda il codice nella tua domanda, entrambe le varianti sono perfettamente valide, ma significano cose diverse. La prima variante dichiara subito un argomento predefinito per il secondo parametro. La seconda variante inizialmente dichiara la tua funzione senza argomenti predefiniti, quindi ne aggiunge una per il secondo parametro.

L'effetto netto di entrambe le dichiarazioni (ovvero il modo in cui viene visto dal codice che segue la seconda dichiarazione) è esattamente lo stesso: la funzione ha argomento predefinito per il suo secondo parametro. Tuttavia, se riesci a spremere del codice tra la prima e la seconda dichiarazione, queste due varianti si comporteranno diversamente. Nella seconda variante la funzione non ha argomenti predefiniti tra le dichiarazioni, quindi dovrai specificare entrambi gli argomenti in modo esplicito.


Non penso che il tuo codice definito void foo (int a = 1, int b) funzionerebbe. Devi avere tutti i parametri opzionali dopo un parametro opzionale. È un errore di sintassi (almeno con g ++ 4.5.3 sul mio sistema).
Nilesh,

@Nilesh: Come ho detto esplicitamente sopra (e che è l'intero punto di questo esempio) per void foo(int a = 1, int b)funzionare, deve essere dichiarato dopo void foo(int a, int b = 5) . Sì, funzionerà. E no, non è un errore di sintassi. g ++ 4.5.3 lo compilerà perfettamente.
AnT

Va bene, quindi la funzione prende il valore di b dalla dichiarazione precedente. Capire subito. Grazie :-)
Nilesh,

1
@Nilesh: Sì, le dichiarazioni degli argomenti predefiniti vengono accumulate in tutte le dichiarazioni precedenti nell'unità di traduzione.
AnT

1
Mi piace scrivere i miei prototipi di funzioni senza nomi di variabili, come int foo(int). Trovo di poter scrivere di int foo(int=5)nuovo, tralasciando i nomi dei parametri. Nessuno sembra averlo ancora menzionato.
Victor Eijkhout,

5

Il primo modo sarebbe preferito al secondo.

Questo perché il file di intestazione mostrerà che il parametro è facoltativo e quale sarà il suo valore predefinito. Inoltre, ciò garantirà che il valore predefinito sia lo stesso, indipendentemente dall'implementazione del file .cpp corrispondente.

Nel secondo modo, non vi è alcuna garanzia di un valore predefinito per il secondo parametro. Il valore predefinito potrebbe cambiare, in base alla modalità di implementazione del file .cpp corrispondente.


4

Gli argomenti predefiniti devono essere specificati con la prima occorrenza del nome della funzione, in genere nel prototipo della funzione. Se il prototipo della funzione viene omesso perché la definizione della funzione funge anche da prototipo, è necessario specificare gli argomenti predefiniti nell'intestazione della funzione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.