Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
PartE 2
Eccovi altri interessanti consigli sul C++, questa volta sfruttando lultima
versione disponibile del linguaggio di programmazione: C++11
Shape
Shape
oppure
int *p_int(0);
// o int *p_int = 0; // definisce e
inizializza
p_int = &i;
// imposta p_int perch punti a i
*p_int // utilizza il valore dellintero al quale p_int sta
attualmente puntando
Puntatori a costanti
Potete avere puntatori a valori di sola lettura, per esempio
const. importante notare, comunque, che una dichiarazione
o definizione della forma
const char *p;
(che definisce p come puntatore che il compilatore
controller) utilizzata solo per la lettura del dato puntato.
In altre parole al puntatore p negato laccesso in scrittura
delloggetto al quale punta (in questo caso il target di p un
char, o un array di char, se avesse valore 0 non punterebbe
a nulla). Nel codice che usa p il puntatore stesso non const:
pu essere cambiato, ma la cosa a cui punta (un char o array
di char in questo caso) non pu essere modificata attraverso
di esso. Per oggetti di una classe MyClass con un puntatore
definito cos
MyClass my_obj;
MyClass *p = &my_obj;
// definisce un puntatore p
che punta ad un oggetto pre-esistente (my_obj) del tipo
MyClass
i membri possono essere letti
p->m // valuta il membro m delloggetto my_obj
referenziato dal puntatore
Dal momento che i data member di una classe sono
tipicamente privati e le member function pubbliche,
la convenzione
p->mf(); // invoca la member function mf delloggetto
referenziato da p
Puntatori e array
Fig.1 Loggetto base e il derivato
in memoria. Un oggetto Circle
ha tutti i data member della classe
Circle, pi quelli della classe Shape
(per ereditariet), memorizzati
come mostrato
78
Circle
C++
a runtime, ma la variabile (nome) con la quale larray
definito avr un valore fisso corrispondente allindirizzo
dellarray in memoria. I nomi di array sono dunque trattati
come puntatori costanti. Viceversa, i puntatori possono essere
trattati come se fossero nomi di array allo scopo di indirizzare
elementi di array. quindi possibile scrivere una definizione
di questo tipo, per esempio:
int a[10]; // a un array di 10 int
oppure
MyClass a[10];
// a un array di 10 istanze di MyClass
Puntatori smart
ed ereditariet
Base
Derivata
Fig.2 Una generalizzazione dellesempio in Fig.1
Puntatori e referenze
In molti casi la scelta tra luso dei tipi di puntatori e referenze
questione di gusti o convenzione. Una differenza semantica
importante, tuttavia,
che mentre una
referenza deve
referenziare qualcosa
(un oggetto che
contenuto nella sua
definizione), un puntatore
pu puntare a nulla.
Una funzione che accetta
un parametro per referenza avr loggetto corrispondente
disponibile allinterno della sua definizione; se il parametro
fosse passato come puntatore sarebbe necessario controllare
se il suo valore diverso da 0. Viceversa, una funzione
find(), per esempio, potrebbe ritornare un valore puntatore
indicante dove loggetto stato trovato, se lo stato;
un valore di 0 indicherebbe che loggetto non stato trovato
per nulla. Questa tecnica non sarebbe disponibile se il tipo
di ritorno fosse una referenza, dal momento che questultima
deve necessariamente referenziare un oggetto.
Normalmente
i puntatori possono
puntare solo a membri
del loro tipo
79
C++
essere espansi dinamicamente per registrare elementi
mano a mano che vengono aggiunti, e i distruttori
gestiscono la deallocazione.
Base
Base
Derivata
Puntatore
a classe base
Fig.3 Un puntatore alla classe base pu puntare a un oggetto
del tipo della classe base o (alla parte base di) un oggetto
del tipo di una qualsiasi classe derivata dalla base
Funzioni membro
Dato un oggetto avete visto che potete invocarne una funzione
membro con la sintassi
obj.mf(); // mf() una member function della classe obj
Potete avere diverse classi nel vostro sistema
con una member function chiamata mf.
Il compilatore si occuper di recuperare
quella appropriata per loggetto (obj) interessato
nella chiamata; la effettuer, in altre parole,
in base al tipo di oggetto.
Ereditariet
con funzioni non virtuali
Tip
Ogni directory
degli esempi di
codice contiene
un file Readme.
Leggetelo per
istruzioni sulla
compilazione!
80
Ereditariet
con le funzioni virtuali
Spesso, comunque, il suddetto comportamento non quello
desiderato. Quello che volete invocare la funzione rilevante
per il tipo di oggetto. In casi come quello dellesempio, dove
state iterando con un puntatore a classe base, vorreste che
C++
la funzione fosse scelta in base al tipo delloggetto puntato,
non del puntatore. in maniera simile, potreste avere una
funzione che accetta un parametro di una classe base.
Se lo passaste per valore avreste loggetto classe base
allinterno della funzione, malgrado gli passiate un qualsiasi
derivato. Se passate largomento per puntatore, o riferimento,
al tipo base, e le funzioni rilevanti sono virtuali, allora le funzioni
da chiamare sono determinate in base al tipo delloggetto
puntato o riferito. Questo mostrato nel passo 2 del box
in questa pagina.
Override in azione
in conclusione, quando una funzione ridefinita a vari livelli
(prevalenza o override) in una gerarchia di ereditariet,
la funzione rilevante pu essere chiamata in base al tipo
di oggetto, ammesso che la funzione sia dichiarata come virtuale
nella classe base. Questo si applica in due scenari comuni:
avete una collezione eterogenea di oggetti su cui iterare
con un puntatore a classe base, e volete chiamare la versione
appropriata della funzione prevalente in base al tipo di oggetto;
state passando un oggetto come argomento puntatore
o riferimento a una funzione, e il tipo di parametro usato
un puntatore/riferimento alla classe base.
il concetto e la terminologia usati qui riguardano una funzione
prevalente a vari livelli in una gerarchia dereditariet.
in questo caso la funzione ha un nome e una sequenza di tipi
di parametro a tutti questi livelli (ovvero ha la stessa segnatura).
Anche i tipi di ritorno sono identici, eccetto il fatto che possano
differire restando allinterno, a loro volta, di una gerarchia
dereditariet. Questo diverso dal sovraccarico (overload),
dove le funzioni hanno un nome comune ma diverse
sequenze di parametri.
Esempi
Gli esempi illustrano alcune caratteristiche del C++
proseguendo il disegno, allo scopo di renderizzarlo finalmente
Polimorfismo
81