int div (int dividendo, int divisore) { return dividendo / divisore; } |
double divReale (double dividendo, double divisore) { return dividendo / divisore; } |
double divIntReale (int dividendo, double divisore) { return double(dividendo) / divisore; } double divRealeInt (double dividendo, int divisore) { return dividendo / double(divisore); } |
div
,divReale
,divRealeInt
,divIntReale
), che ben
presto confonderemo. Questo modo di procedere è molto scomodo, sebbene sia
utilizzato comunemente in linguaggi diversi dal C++, i quali non permettono la
sovrapposizione delle funzioni. In C++ invece si identificano tutte le funzioni con il medesimo nome, poi ci penserà il compilatore a scegliere la funzione appropriata. Bellissimo: le funzioni per dividere due numeri (interi o reali) restano quattro, ma il nome è unico, così la probabilità di fare confusione tra i diversi nomi è ridotta a zero. Avremo allora:
// ex5_6_1.cpp #include <iostream.h> int div (int divisore, int dividendo) { cout << "\ndivisione tra due interi: "; return divisore / dividendo; } double div (double divisore, double dividendo) { cout << "\ndivisione tra due reali: "; return divisore / dividendo; } double div (int divisore, double dividendo) { cout << "\ndivisione intero per reale: "; return double(divisore) / dividendo; } double div (double divisore, int dividendo) { cout << "\ndivisione reale per intero: "; return divisore / double(dividendo); } void main() { cout << div (15, 3); cout << div (37.5, 2.0); cout << div (37, 2.0); cout << div (37.5, 2); }
output:
divisione tra due interi: 5
divisione tra due reali: 18.75
divisione intero per reale: 18.5
divisione reale per intero: 18.75
All'interno di ciascuna funzione abbiamo inserito un comando di stampa, al fine di evidenziare quale è in realtà la funzione chiamata dal compilatore, in maniera del tutto automatica. Naturalmente non solo le funzioni matematiche possono essere sovrapposte; vediamo due esempi di sovrapposizione di funzioni non matematiche:
// ex5_6_2.cpp // modifica dell'esempio ex5_5_4.cpp #include <iostream.h> void scambia (int* a, int* b) { int t = *a; *a = *b; *b = t; } void scambia (int& a, int& b) { int t = a; a = b; b = t; } void main() { int a = 3, b = 7; cout << "a = " << a << "\tb = " << b << "\n"; scambia (&a, &b); cout << "a = " << a << "\tb = " << b << "\n"; scambia (a, b); cout << "a = " << a << "\tb = " << b << "\n"; }
output:
a = 3 | b = 7 | |
a = 7 | b = 3 | |
a = 3 | b = 7 |
Come si vede un programma che sovrappone le funzioni, risulta molto più leggibile e semplice da utilizzare di uno ad esso equivalente, che abbia nomi diverse per funzioni che svolgono la stessa mansione. Andiamo avanti.
// ex5_6_3.cpp #include <iostream.h> #include <math.h> void messaggio () { cout << "benevenuto!\n" "questo programma calcola la radice quadrata\n" "algebrica di un numero reale dato\n" "scrivi un numero negativo per terminare"; } void messaggio (double x) { cout << "l'unica radice e': " << x; } void messaggio (double x1, double x2) { cout << "le radici sono: " << x1 << " e " << x2; } void main() { double argomento; messaggio(); do { cout << "\n? "; cin >> argomento; if (argomento > 0) { double x1 = sqrt (argomento); double x2 = -x1; messaggio (x1, x2); } else if (argomento == 0) messaggio (0); } while (argomento >= 0); }
esempio di output:
benevenuto!
questo programma calcola la radice quadrata
algebrica di un numero reale dato
scrivi un numero negativo per terminare
? 9
le radici sono: 3 e -3
? 7
le radici sono: 2.64575 e -2.64575
? 0
l'unica radice e': 0
? -1
In questo esempio la sovrapposizione non è avvenuta in base al tipo degli argomenti, bensì secondo il loro numero. Si noti che funzioni sovrapposte possono avere tipo di ritorno diversi, ma non è possibile sovrapporre due funzioni che differiscano solo nel ritorno, perché potrebbero crearsi ambiguità nelle chiamate di funzione. Vediamo un ultimo esempio:
// ex5_6_4.cpp #include <iostream.h> #include <math.h> const double PI = 3.14159265358979323846264338327; // gg = gradi, mm = minuti, ss = secondi double sin (int gg, int mm, int ss) { double gradiDecimali = gg + double(mm) / 60.0 + double(ss) / 3600.0; double radianti = gradiDecimali * PI / 180; return sin(radianti); } void main() { cout << sin (PI / 6) << "\n"; // .5 cout << sin (28, 60, 3600); // .5 }
Questo esempio mostra come sia possibile sovrapporre anche le funzioni di libreria (nel caso specifico la sin
), per meglio adattarle agli scopi dei nostri programmi.
math.h
per calcolare il coseno e la tangente, in maniera tale da poterle utilizzare anche con angoli in gradi;