Esempio: corretto:
void hello(); // questa funzione non ha alcun parametro int about (int, char); foo (int); // il tipo di ritorno di default è interrato:
void hello(); ... void foo() { hello (10); }quest'ultimo genererà l'errore: "chiamata alla funzione indeterminata (cioè non definita)
hello (int)
" oppure "troppi argomenti
alla funzione void hello()
" e simili.
Ndt: notare che in C non si aveva quell'errore. Per saperne di più vedere il Kernighan-Ritchie, paragrafo 1.7
Nota che il nome di un parametro nel prototipo non è obbligatorio, solo il suo tipo è richiesto. Se il tipo di ritorno viene omesso, viene utilizzato int come default.
Non c'è bisogno di usare un prototipo nel codice sorgente se la funzione è chiamata dopo la sua definizione. Esempio:
// void hello(); Linea non obbligatoria void hello() { printf ("hello world.\n"); } void foo() { hello(); }
Esempio:
int foo (int a, int b) { return a * b; } int foo (int a) { return a * 2; } ... { a = foo (5, 5) + foo (5); // ritorna 5 * 5 (risultato della prima foo) } // + 5 * 2 (risultato della seconda foo)Ma possono sorgere dei problemi. Ad es. puoi definire due funzioni in questo modo:
int add (int a, int b); float add (float a, float b);e poi fare una chiamata ad add. Questo tipo di definizioni vanno evitate. I compilatori si confondono e danno warning o errori a seconda dei casi, corrispondenti a perdite di informazioni o ambiguità della situazione.
Ndt: vi invito a sperimentare la situazione col vostro compilatore. Provate a definire entrambe le funzioni in modo che restituiscono a+b. Se si compila provate poi a chiamare add con due interi, due float, con un intero e un float e viceversa. Potete stabilire quale funzione add viene chiamata tracciando il programma o facendo stampare da ciascuna delle funzioni un messaggio indicativo con una printf.
Quella che abbiamo visto era una situazione di ambiguità pericolosa. Ma che ne dite di questa?
int add (int a, float b); float add (float a, int b); ... a = add (2, 2);Fortunatamente, il compilatore rifiuterà sicuramente quel codice, spiegando che non può scegliere tra le due funzioni funzioni add. Perciò fai attenzione!
Esempio:
int foo (int a, int b = 5); ... int foo (int a, int b) { return a * b; } { a = foo (2); // Dà lo stesso risultato di a = foo (2, 5); }Nota che puoi assegnare dei valori di default solo ad un ultimo gruppo di parametri, altrimenti il compilatore non saprebbe a quale parametro assegnare il valore di default...
int func1 (int = 0, char); // Non permesso void func2 (char, int = 0); // OkUn valore di default deve essere specificato nel prototipo, e non necessariamente ripetuto nella definizione della funzione. Infatti, quando specifici dei valori di default, in realtà è come se implicitamente stessi definendo molte funzioni con lo stesso nome. In un esempio precedente, quando abbiamo scritto:
int foo (int a, int b = 5);
foo (int)
e foo (int, int)
sono state prototipate e
quindi implicitamente definite.
Pertanto notiamo che combinando valori di default dei parametri con l'overloading delle funzioni, possiamo produrre situazioni ambigue vietate, come questa:
int foo (int a, int b = 5); // Definizione con valore di default per b int foo (float a); // Altra definizione di foo: produce ambiguità int foo (int a); // Errore: conflitto con la prima definizione