I namespace
Il secondo problema che si verifica con la ripartizione di un progetto in piu`
file e` legato alla necessita` di utilizzare identificatori globali unici. Quello
che spesso accade e` che al progetto lavorino piu` persone ognuna delle quali
si occupa di parti diverse che devono poi essere assemblate. Per quanto possa
sembrare difficile, spesso accade che persone che lavorano a file diversi utilizzino
gli stessi identificatori per indicare funzioni, variabili, costanti...
Pensate a due persone che devono realizzare due moduli ciascuno dei quali prima
di essere utilizzato vada inizializzato, sicuramente entrambi inseriranno nei
rispettivi moduli una funzione per l'inizializzazione e molto probabilmente
la chiameranno InitModule() (o qualcosa di simile). Nel momento
in cui i due moduli saranno linkati insieme (e sempre che non siano sorti problemi
prima ancora), inevitabilmente il linker segnalera` errore.
Naturalmente basterebbe che una delle due funzioni avesse un nome diverso, ma
modificare tale nome richiederebbe la modifica anche dei sorgenti in cui il
modulo e` utilizzato. Molto meglio prevenire tale situazione suddividendo lo
spazio globale dei nomi in parti piu` piccole (i namespace) e
rendere unicamente distinguibili tali parti, a questo punto poco importa se
in due namespace distinti un identificatore appare due volte... Ma vediamo un
esempio:
// File MikeLib.h
namespace MikeLib {
typedef float PiType;
PiType Pi = 3.14;
void Init();
}
// File SamLib.h
namespace SamLib {
typedef double PiType;
PiType Pi = 3.141592;
int Sum(int, int);
void Init();
void Close();
}
In una situazione di questo tipo non ci sarebbe piu` conflitto tra le definizioni
dei due file, perche` per accedere ad esse e` necessario specificare anche l'identificatore
del namespace:
#include "MikeLib.h"
#include "SamLib.h"
int main(int, char* []) {
MikeLib::Init();
SamLib::Init();
MikeLib::PiType AReal = MikeLib::Pi * 3.7;
Areal *= Pi; //
Errore!
SamLib::Close();
}
L'operatore :: e` detto risolutore di scope e indica
al compilatore dove cercare l'identificatore seguente. In particolare l'istruzione
MikeLib::Init(); dice al compilatore che la Init()
cui vogliamo riferirci e` quella del namespace MikeLib . Ovviamente
perche` non ci siano conflitti e` necessario che i due namespace abbiano nomi
diversi, ma e` piu` facile stabilire pochi nomi diversi tra loro, che molti.
Si noti che il tentativo di riferire ad un nome senza specificarne il namespace
viene interpretato come un riferimento ad un nome globale esterno ad ogni namespace
e nell'esempio precedente genera un errore perche` nello spazio globale non
c'e` alcun Pi .
I namespace sono dunque dei contenitori di nomi su cui sono defite delle regole
ben precise:
- Un namespace puo` essere creato solo nello scope globale;
- Se nello scope globale di un file esistono due namespace con lo stesso
nome (ad esempio i due namespace sono definiti in file header diversi, ma
inclusi da uno stesso file), essi vengono fusi in uno solo;
- E` possibile creare un alias di un namespace con la sintassi:
namespace
< ID1 > = < ID2 > ;
- E` possibile avere namespace anonimi, in questo caso gli identificatori
contenuti nel namespace sono visibili al file che contiene il namespace anonimo,
ma essi hanno tutti automaticamente linkage interno. I namespace anonimi di
file diversi non sono mai fusi insieme.
|