Rettangolo
o puntatori o riferimenti
ad essi. Vediamo un esempio contenente un puntatore ad un oggetto di tipo
struttura:
// ex7_5_1 #include <iostream.h> #include <string.h> struct Figura { int x; // posizione, ascissa int y; // posizione, ordinata double scala; // fattore di scala char nome[20]; // nome della figura }; void main() { Figura f; f.x = 150; f.y = 70; f.scala = 1.5; strcpy (f.nome, "quadrato"); Figura* p = &f; (*p).x = 300; cout << f.x << "\n"; }
output:
300
Si noti che nello statement
(*p).x = 300; |
x
dell'oggetto puntato da p
'' piuttosto
che ``l'oggetto puntato dal campo x
di p
''; tale sintassi è
piuttosto scomoda, in quanto poco intuitiva e facile da confondere; è stato
allora introdotto in C++ un nuovo operatore, che funge da sinonimo sintattico
all'operatore ``campo di'' se l'oggetto è un puntatore: l'operatore
``freccia'' (->
). Avremmo ad esempio potuto scrivere, al posto di
(*p).x = 300;
p->x = 300; |
// ex7_5_2 #include <iostream.h> #include <string.h> struct Figura { int x; // posizione, ascissa int y; // posizione, ordinata double scala; // fattore di scala char nome[20]; // nome della figura }; // passaggio per indirizzo // con puntatore costante void stampa (const Figura* p) { cout << "figura: " << p->nome << "\n" << "posizione (" << p->x << ", " << p->y << ")\n" << "scala 1:" << p->scala << "\n"; } // passaggio per indirizzo // con puntatore NON costante: // l'argomento viene modificato void sposta (Figura* p, int x, int y) { p->x = x; p->y = y; } void main() { Figura f; f.x = 150; f.y = 70; f.scala = 1.5; strcpy (f.nome, "quadrato"); stampa (&f); sposta (&f, 80, 25); stampa (&f); }
output:
figura: quadrato
posizione (150, 70)
scala 1:1.5
figura: quadrato
posizione (80, 25)
scala 1:1.5
L'operatore `->
' è molto usato; infatti è piuttosto comune
utilizzare puntatori a oggetti complessi, come le strutture, spesso perché
essi vengono allocati dinamicamente. Comunque è importante capire che
l'operatore `->
' non è altro che un sinonimo dell'operatore
`.
', nel caso l'oggetto sia un puntatore.
Poniamoci a questo punto una domanda: è possibile inizializzare oggetti di tipo struttura? La risposta è affermativa; tuttavia inizializzare un oggetto costituito da tanti oggetti di diverso tipo corrisponde ad inizializzare ogni campo della struttura; per compiere tale operazione in un solo statement abbiamo bisogno di un nuovo strumento messo a disposizione dal C++: il costruttore. Quando tratteremo le classi, vedremo meglio l'importanza che ha il costruttore nella creazione di nuovi tipi; per ora impareremo soltanto ad utilizzarlo nelle sue funzionalità base. Un costruttore è una funzione interna ad una struttura, la quale specifica come inizializzare i campi di una istanza (cioè un oggetto) di tale struttura; esso viene chiamato automaticamente una ed una sola volta al momento della creazione dell'oggetto; il nome della funzione costruttore è obbligatoriamente lo stesso nome della struttura. Vediamo un esempio:
// ex7_5_3 #include <iostream.h> struct Rettangolo { int larg; int alt; Rettangolo () { // costruttore larg = 50; alt = 20; } }; void main() { Rettangolo r; cout << "larg = " << r.larg << "\n" << "alt = " << r.alt << "\n"; }
output:
larg = 50
alt = 20
La funzione costruttore all'intero della struttura Rettangolo
ha come
compito quello di impostare dei valori iniziali ai campi larg
e
alt
; nulla vieta che solo alcuni dei campi dati della struttura vengano
inizializzati, ma si sconsiglia tale pratica perché fuorviante: per quale
motivo un utilizzatore del nostro codice dovrebbe aspettarsi che il
costruttore inizializzi solo alcuni campi lasciando gli altri fluttuanti?
Il costruttore può avere anche degli argomenti, spesso corrispondenti a ciascun campo da inizializzare:
// ex7_5_4 #include <iostream.h> #include <string.h> struct Libro { char* titolo; int costo; bool disponibile; Libro (char* Titolo, int Costo, bool Disponibile) { titolo = new char[strlen(Titolo) + 1]; strcpy (titolo, Titolo); costo = Costo; disponibile = Disponibile; } }; void stampa (const Libro& a) { cout << a.titolo << "\n" << "costo: " << a.costo << "\n"; if (a.disponibile == true) cout << "disponibile" << "\n"; else cout << "non disponibile" << "\n"; } void main() { // Libro a; // NO Libro a ("2000: Space odissey", 32000, true); Libro* b = new Libro ("Shining", 25000, false); stampa (a); stampa (*b); }
output:
2001: Space odissey
costo: 32000
disponibile
Shining
costo: 25000
non disponibile
Come si vede l'inizializzazione di un oggetto struttura è semplice e immediata; si noti bene che se esiste un costruttore in una struttura, non è possibile creare un oggetto di tale struttura senza fornire i parametri opportuni al costruttore. Tuttavia è possibile avere più di un costruttore per ciascuna struttura, sfruttando la nota tecnica di overloading delle funzioni; ad esempio
// ex7_5_5 #include <iostream.h> enum Colore { ROSSO, VERDE, BLU, CIANO, MAGENTA, GIALLO, BIANCO, NERO }; struct Tazza { Colore col; double diametro; double capacita; Tazza (Colore Col, double Diametro, double Capacita) { col = Col; diametro = Diametro; capacita = Capacita; } Tazza (double Diametro, double Capacita) { col = ROSSO; diametro = Diametro; capacita = Capacita; } Tazza () { col = ROSSO; diametro = 8; capacita = 200; } }; void stampa (const Tazza& t) { char c[10]; switch (t.col) { case ROSSO: strcpy (c, "rosso"); break; case VERDE: strcpy (c, "verde"); break; case BLU: strcpy (c, "blu"); break; case CIANO: strcpy (c, "ciano"); break; case MAGENTA: strcpy (c, "magenta"); break; case GIALLO: strcpy (c, "giallo"); break; case BIANCO: strcpy (c, "bianco"); break; case NERO: strcpy (c, "nero"); break; } cout << c << "\t" << t.diametro << "\t" << t.capacita << "\n"; } void main() { Tazza t1 (VERDE, 10, 250); Tazza t2 (6, 140); Tazza t3; stampa (t1); stampa (t2); stampa (t3); }
output:
verde | 10 | 250 | |
rosso | 6 | 140 | |
rosso | 8 | 200 |
Comunque l'argomento riguardante i costruttori verrà approfondito ampiamente durante la trattazione delle classi; abbiamo introdotto tale costrutto a proposito delle struttura solo perché potremo farne uso nei prossimi paragrafi, nei quali presenteremo le liste; in realtà utilizzare costruttori nelle strutture non è comune, se non appunto in particolari casi.