# Dal C al C++/Utilizzo basilare di librerie/Le funzioni standard

Dal C al C++
Copertina Tutti i moduli · Sviluppo
* IntroduzioneDal C al C++/Introduzione
** I destinatari del libroDal C al C++/Introduzione#I destinatari del libro
** La struttura del libroDal C al C++/Introduzione#La struttura del libro
** Impieghi del linguaggioDal C al C++/Introduzione#Impieghi del linguaggio
** PanoramicaDal C al C++/Introduzione#Panoramica
* Utilizzo basilare di librerie
** ArrayDal C al C++/Array
** Il tipo "bool"Dal C al C++/Utilizzo basilare di librerie/Il tipo "bool"
** L'uso di classi e oggettiDal C al C++/Utilizzo basilare di librerie/L'uso di classi e oggetti
** Dichiarazioni e definizioniDal C al C++/Utilizzo basilare di librerie/Dichiarazioni e definizioni
*** Le variabili riferimentoDal C al C++/Utilizzo basilare di librerie/Dichiarazioni e definizioni#Le variabili riferimento
*** Il modificatore "const"Dal C al C++/Utilizzo basilare di librerie/Dichiarazioni e definizioni#Il modificatore "const"
*** Il sovraccaricamentoDal C al C++/Utilizzo basilare di librerie/Dichiarazioni e definizioni#Il sovraccaricamento
*** L'inizializzazione degli oggettiDal C al C++/Utilizzo basilare di librerie/Dichiarazioni e definizioni#L'inizializzazione degli oggetti
*** L'allocazione degli oggettiDal C al C++/Utilizzo basilare di librerie/Dichiarazioni e definizioni#L'allocazione degli oggetti
** L'uso dei templateDal C al C++/Utilizzo basilare di librerie/L'uso dei template
** L'uso dei namespaceDal C al C++/Utilizzo basilare di librerie/L'uso dei namespace
** I file di intestazioneDal C al C++/Utilizzo basilare di librerie/I file di intestazione
** L'uso delle stringheDal C al C++/Utilizzo basilare di librerie/L'uso delle stringhe
** I canali di ingresso/uscitaDal C al C++/Utilizzo basilare di librerie/I canali di ingresso/uscita
** La gestione delle eccezioni
** I contenitori standardDal C al C++/Utilizzo basilare di librerie/I contenitori standard
** Le funzioni standardDal C al C++/Utilizzo basilare di librerie/Le funzioni standard
* Utilizzo avanzato di librerie
** Ridefinizione di funzioni membroDal C al C++/Utilizzo avanzato di librerie/Ridefinizione di funzioni membro
** I parametri di defaultDal C al C++/Utilizzo avanzato di librerie/I parametri di default
** Gli iteratori sui contenitori
** Gli algoritmi sui contenitori
* Creazione di librerie
** Classi isolateDal C al C++/Classi isolate
*** I costruttoriDal C al C++/Classi isolate#I costruttori
*** I distruttoriDal C al C++/Classi isolate#I distruttori
*** Separazione tra interfaccia e implementazioneDal C al C++/Classi isolate#Separazione tra interfaccia e implementazione
** Gerarchie di classiDal C al C++/Gerarchie di classi
** Proprietari di risorse
** Eccezioni
** Namespace
** Template di funzione
** Template di classe
** Algoritmi su sequenze
* La metaprogrammazione
* La progettazione del software
* Gioco life di ConwayDal C al C++/Gioco life di Conway
Modifica il sommario
La libreria standard del C++ contiene numerose funzioni che non sono membro di qualche classe. Ecco un programma che mostra l'uso delle funzioni più importanti ("swap", "min", "max", "abs"):
Questo programma stampa le seguenti righe:
Le funzioni "swap", "min" e "max" sono chiamate due volte; la prima volta ricevono due variabili di tipo "int", mentre la seconda volta due variabili di tipo "string". Ovviamente, in un linguaggio a tipizzazione statica come il C++, la medesima funzione non può accettare come parametri valori di vari tipi, a meno che esista una conversione implicita dal tipo del valore al tipo del parametro. Siccome non esiste una conversione implicita né dal tipo "int" al tipo "string", né dal tipo "string" al tipo "int", né da entrambi i tipi a un terzo tipo, si deduce che esistono più versioni delle funzioni citate.
Tale molteplicità di versioni si può ottenere con i template di funzione, oppure con le funzioni sovraccaricate. In effetti, "min" e "max" sono template di funzione, "abs" è un insieme di funzioni sovraccaricate, mentre "swap" è un insieme di template di funzioni e di funzioni sovraccaricate. Pertanto, invece che parlare di funzioni sarebbe più corretto parlare di famiglie di funzioni.
In seguito vengono ripetute e analizzate porzioni del programma mostrato sopra.

### Le famiglie di funzioni matematiche

Si consideri questo programma:
Questo programma stampa "3.2". La chiamata ad "abs" prende come parametro un numero non intero ("-3.2") e rende un numero non intero ("3.2").
Nella libreria standard del C esiste una funzione chiamata "abs", ma prende un "int" e rende un "int". Passandogli un valore "double", questo viene prima troncato a "int" e poi gli viene tolto il segno. Pertanto, in linguaggio C, dopo aver eseguito l'istruzione "double a = abs(-3.2)", la variabile "a" vale "3.".
Questo è uno dei rari casi in cui la compatibilità tra il C e il C++ è solo parziale. Infatti, in linguaggio C++, dopo aver eseguito l'istruzione appena citata, la variabile "a" vale "3.2".
In linguaggio C, per ottenere lo stesso risultato, si deve usare la funzione "fabs", che prende un "double" e rende un "double". In C++, la funzione "fabs" è stata mantenuta per compatibilità, ma è considerata obsoleta, in quanto la nuova famiglia di funzioni "abs" si applica a tutti i tipi di dati numerici.
Nel file di intestazione "cmath" sono dichiarate numerose versioni sovraccaricate di "abs". C'è la versione che prende un "int" e rende un "int" ereditata dal C, ma ce ne sono altre quattro: una che prende un "long" e rende un "long", una che prende un "float" e rende un "float", una che prende un "double" e rende un "double", e una che prende un "long double" e rende un "long double".
Non ci sono versioni per "char", e "short", quindi tali valori vengono implicitamente convertiti in "int".
Inoltre, nel file di intestazione "complex" c'è un'altra versione di "abs", che prende un numero complesso e rende un altro numero complesso.
Questa molteplicità di versioni della stessa funzione per tipi diversi non è esclusiva della funzione "abs". Per molte altre funzioni matematiche ereditate dal C, come "sqrt", "floor", "pow", che in linguaggio C gestivano solamente numeri "double", in C++ esistono versioni per vari tipi.
Avere più versioni della stessa funzione consente di ottimizzare le prestazioni per il tipo di dato da elaborare.

### La famiglia di funzioni "min" e "max"

Si consideri questo programma:
Questo programma stampa le seguenti righe:
Le prime chiamate a "min" e a "max" ricevono due valori di tipo "int", e, da come risulta in stampa, rendono un "int". Le seconde chiamate a "min" e a "max" ricevono due valori di tipo "string", e, da come risulta in stampa, rendono un oggetto di tipo "string".
Per ottenere questo effetto è bastato definirle come template di funzioni. Qualunque sia il tipo dei loro parametri, queste funzioni rendono un valore dello stesso tipo.
Le uniche condizioni da rispettare sono due:
* I due parametri devono essere dello stesso tipo.
* Deve essere definito l'operatore "<" tra i parametri.
La seconda condizione si applica sia a numeri interi che a oggetti "string", ma non a tutti gli oggetti. Si consideri il seguente programma:
Prima di tutto si noti che è stata commentata la seconda riga della funzione "main", in quanto illegale. La funzione "min" non si può applicare ai numeri complessi, in quanto tra di essi non è definito l'operatore "<".
Il resto del programma stampa qualcosa, che però non è ben definito dal linguaggio. Probabilmente è "x1 abc", oppure "abc x2".
Passare dei puntatori a carattere alla funzione "min", non significa passarle delle stringhe; significa passarle dei puntatori. La funzione rende quello dei due puntatori avente valore inferiore. Per valore di un puntatore, si intende il suo indirizzo di memoria.
Se, come è ragionevole, il compilatore alloca le stringhe letterali nell'ordine con cui le trova, in memoria ci sarà qualcosa del genere: "x1(NUL)abc(NUL)x2(NUL)", dove l'espressione "(NUL)" indica lo zero binario. Se invece, come pure è ragionevole, il compilatore alloca le stringhe letterali nell'ordine inverso, in memoria ci sarà qualcosa del genere: "x2(NUL)abc(NUL)x1(NUL)". In entrambi i casi si ha che il puntatore "p2" ha un valore intermedio tra quello di "p1" e quello di "p2", per cui risulterà minore di una e maggiore dell'altro. Ma non si possono del tutto escludere altri risultati.

### La famiglia di funzioni "swap"

Si consideri questo programma:
Questo programma stampa le seguenti righe:
La prima chiamata a "swap" scambia il contenuto delle variabili "a" e "b". Infatti, quando viene stampato prima "a" e poi "b", viene emesso "7, 5", che sono i valori originali scambiati.
Un funzione di libreria non può modificare dei valori esterni ricevendone solo una copia; deve ricevere l'indirizzo o il riferimento a tali valori. Come si vede, nella chiamata a "swap" non vengono passati indirizzi, quindi entrambi i parametri devono essere passati per riferimento.
Per scambiare il contenuto di due oggetti, la funzione swap deve copiare un numero di bit che dipende dalla dimensione degli oggetti stessi. Per poter funzionare correttamente, deve essere un template che viene istanziato per ogni tipo di oggetto per cui viene chiamato.
In realtà, la sola definizione di un temlplate introdurrebbe delle inefficienze nei casi in cui la copia dell'oggetto è costosa. Per esempio, se passando a "swap" due oggetti di tipo "vector" venissero copiati gli interi vettori di dati, l'operazione sarebbe terribilmente lenta. Pertanto, per alcune classe, per esempio per "vector" e "string", sono definite nella libreria standard delle versioni sovraccaricate di "swap", che sono molto efficienti.