Lezione del 10/7/2006¶
-
Nuove funzionalita’ del C++ rispetto al C: L’overloading
File ex001.cc
1/* 2 * Cosa ha in piu' in C++ a basso livello. 3 * 4 */ 5 6/* 7 * Il commento su singola riga. 8 * dopo i caratteri // 9 * tutto quello che segue fino a fine riga e' ignorato 10 */ 11 12// questo e' un commento 13// e' simile al ! del FORTRAN 90 14 15 16/* 17 * OVERLOADING 18 * 19 */ 20 21// MAX versione 1 (tra interi) 22// Esempio, voglio definire una funzione massimo tra due interi 23int 24max( int a, int b ) { 25 if ( a > b ) return a ; 26 else return b ; 27} 28 29// MAX versione 2 (tra doppia precisione) 30// Se ora voglio definire le funzione massino tra "double" 31// in C non posso scrivere 32double 33max( double a, double b ) { 34 if ( a > b ) return a ; 35 else return b ; 36} 37 38// MAX versione 3 (tra doppia interi lunghi senza segno) 39// Se ora voglio definire le funzione massino tra "unsigned long long" 40// in C non posso scrivere 41unsigned long long 42max( unsigned long long a, unsigned long long b ) { 43 if ( a > b ) return a ; 44 else return b ; 45} 46 47int 48main() { 49 int a = 1 ; // definisco e inizializzo una variabile intera 50 int b = 2 ; // definisco e inizializzo una variabile intera 51 int c = max(a,b) ; // USO MAX VERSIONE 1 52 53 // posso definire e inizializzare variabili nuove 54 // in qualunque del codice (SONO C++) 55 double fa = 1 ; // definisco e inizializzo una variabile doppia precisione 56 double fb = 2 ; // definisco e inizializzo una variabile doppia precisione 57 double fc = max(fa,fb) ; // USO MAX VERSIONE 2 58 59 unsigned long long ulla = 1 ; 60 unsigned long long ullb = 2 ; 61 unsigned long long ullc = max(ulla,ullb) ; // USO MAX VERSIONE 3 62 63} 64 65/* 66 67 ASSEMBLER GENERATO DAL COMPILATORE gcc DELLA gnu (versione 4.0.1) 68 69 70 il comando e': gcc -fverbose-asm -S -O2 ex001.cc 71 72 -S = ferma la compilazione alla fase di generazione dell'assembler 73 -fverbose-asm = mette qualche commento all'assembler in modo che 74 sia piu' leggibile 75 -O2 = -O e' il livello di ottimizzazione 76 -O0 nessuna ottimizzazione -O3 massima ottimizzazione 77 78 79 80 .text 81 .align 2 82 .p2align 4,,15 83 .globl __Z3maxii 84 85 ;;;; ROUTINE MAX tra interi 86 ;;;; nei registri r3 r4 sono passati gli argomenti a e b 87 88 __Z3maxii: 89 LFB2: 90 cmpw cr7,r3,r4 ; b, tmp121, a 91 bgtlr cr7 ;;; se a < b ritorna dalla routine 92 mr r3,r4 ; a, b ;;; copia il resitro r3 (a) nel registro r4 (valore di ritorno) 93 blr ;;; ritorna dalla rotine 94 LFE2: 95 .align 2 96 .p2align 4,,15 97 .globl __Z3maxdd 98 99 ;;;; ROUTINE MAX tra doppia precisione 100 ;;;; nei registri f1 f2 sono passati gli argomenti a e b 101 ;;;; fn sono i registri floating point della FPU 102 103 ;;;; fsub x,y,z --> z = x-y 104 ;;;; fneg x,y --> x = -y 105 ;;;; fsel r,t,a,b --> se t > 0 r = a altrimenti r = b 106 ;;;; blr --> return dalla subroutine 107 108 __Z3maxdd: 109 LFB3: 110 fsub f0,f1,f2 ; tmp123, a, b ;; f0 = f1-f2 = a-b 111 fsel f1,f0,f1,f2 ; tmp124, tmp123, a, b ;;; istruzione inutile ? 112 fneg f0,f0 ; tmp125, tmp123 ;;;; f0 = |f0| = |a-b| 113 fsel f1,f0,f2,f1 ; <result>, tmp125, b, tmp124 114 blr ; 115 116 ;;;; ROUTINE MAX tra interi lunghi 117 ;;;; nei registri (r3,r4) ed (r5,r6) sono passati gli argomenti a e b 118 ;;;; cioe' uso una coppia di registri per ogni argomento 119 ;;;; questo perche i registri sono di 4 byte e gli argomenti sono di 8 byte 120 ;;;; I registri (r5,r6) contengono il valore in uscita 121 122 LFE3: 123 .align 2 124 .p2align 4,,15 125 .globl __Z3maxyy 126 __Z3maxyy: 127 LFB4: 128 cmplw cr7,r3,r5 ; b, tmp121, a ;; contronfo la parte "alta" del numero intero 129 bgtlr cr7 130 cmpw cr7,r3,r5 ; b, tmp122, a 131 bne cr7,L13 ; 132 cmplw cr7,r4,r6 ; b, tmp123, a ;; confronto la parte "bassa" del numero intero 133 bgtlr cr7 134 .p2align 4,,15 135 L13: 136 mr r3,r5 ; a, b 137 mr r4,r6 ; a, b 138 blr 139 LFE4: 140 .align 2 141 .p2align 4,,15 142 .globl _main 143 _main: 144 LFB5: 145 li r3,0 ; <result>, 146 blr ; 147 LFE5: 148 149*/
File ex002.cc
1/* 2 * Cosa ha in piu'in C++ a basso livello. 3 * 4 */ 5 6/* 7 * OVERLOADING 8 * 9 */ 10 11// SOMMA versione 1 (tra interi) 12// Esempio, voglio definire una funzione che somma due interi 13int 14somma( int a, int b ) { return a+b ; } 15 16// SOMMA versione 2 (tra interi) 17// Esempio, voglio definire una funzione che somma due interi 18// ma voglio restituire il risultato in un intero lungo 19long long 20somma( int a, int b ) { return a+b ; } 21/// NON SI PUO' FARE!!! 22 23 24/* 25 OCCHIO !!!!!!!!!!!!! 26 27 il compilatore distingue routine con lo stesso nome 28 e argomenti diversi. 29 Non c'e' traccia dell'argomento di ritorno per scelta, 30 infatti i meccanismi di conversione e promizione verrebbero 31 notevolmente complicati se questo venisse permesso. 32*/ 33 34int 35main() { 36 int a = 1 ; // definisco e inizializzo una variabile intera 37 int b = 2 ; // definisco e inizializzo una variabile intera 38 float c = somma(a,b) ; // ammesso che compili somma versione 1 e 2 39 // non sa se usare versione 1 o versione 2 40 41 42}
-
Nuove funzionalita’ del C++ rispetto al C: funzioni inline
File ex003.cc
1/* 2 * Cosa ha in piu'in C++ a basso livello. 3 * 4 */ 5 6/* 7 * FUNZIONI INLINE 8 * 9 */ 10 11// FUNZIONE versione 1 (tra interi) 12// Se la funzione come in questo caso e' molto semplice, il tempo 13// perso a fare la chiamata e' paragonabile se non superiore 14// al tempo di esecuzione della routine stessa. 15extern 16int 17funzione( int a, int b ); 18 19// FUNZIONE versione 2 (tra interi) 20// per evitare la chiamata alla funzione, uso la direttiva inline 21// in questo modo la funzione somma_inline non viene "richiamata" 22// ma "espansa" nel punto di chiamata 23 24inline // dichiaro la funzione come "inline" 25int 26funzione_inline( int a, int b ) { 27 int c = a+b ; 28 return c*c ; 29} 30 31int 32esempio(int a, int b) { 33 int c = funzione(a,b) ; 34 int d = funzione_inline(a,b) ; 35 int e = c-d ; 36 return e ; 37} 38 39int 40main() { 41 int result = esempio( 1, 2 ); 42 return 1 ; 43} 44 45/* 46 47 CODICE ASSEMBLER GENERATO 48 49 ;;;; funzione esempio 50 ;;;; i registri r3 ed r4 contengono gli argomenti 51 ;;;; il risultato e' passato nel registro r3 52 53 .text 54 .align 2 55 .p2align 4,,15 56 .globl __Z7esempioii 57__Z7esempioii: 58 59 ;;;; deve costruire int c = funzione(a,b) ; 60 ;;;; 61LFB3: 62 mflr r0 ;, 63LCFI0: 64 stmw r28,-16(r1) ;, ;;;; prepara lo stack per l'indirizzo di ritorno 65LCFI1: 66 mr r28,r4 ; b, b ;;;; copia i valori dei registri r3 e r4 67 mr r29,r3 ; a, a ;;;; nei registri r28 e r29 68 stw r0,8(r1) ;, 69LCFI2: 70 stwu r1,-80(r1) ;,, 71LCFI3: 72 add r29,r29,r28 ; c, a, b ;;;;; queste due righe di assembler 73 mullw r29,r29,r29 ; tmp124, c, c ;;;;; sono l'espansione della funzione inline 74 bl L__Z8funzioneii$stub ; ;;;;; chiamata della funzione fuzione(r3,r4) 75 76 addi r1,r1,80 ;,, 77 subf r3,r29,r3 ; <result>, tmp124, ;;;; esegue r3 = c-d 78 79 lwz r0,8(r1) ;, ;;;; operazione varie da fare per il return della routine 80 lmw r28,-16(r1) ;, 81 mtlr r0 ;, 82 blr ; 83 84 ;;;; programma PRINCIPALE 85 86LFE3: 87 .align 2 88 .p2align 4,,15 89 .globl _main 90_main: 91LFB4: 92 mflr r0 ;, 93LCFI4: 94 li r3,1 ;, 95 li r4,2 ;, 96 stw r0,8(r1) ;, 97LCFI5: 98 stwu r1,-80(r1) ;,, 99LCFI6: 100 bl L__Z8funzioneii$stub ; 101 addi r1,r1,80 ;,, 102 li r3,1 ; <result>, 103 lwz r0,8(r1) ;, 104 mtlr r0 ;, 105 blr ; 106LFE4: 107 108 109*/
File ex004.cc
1/* 2 * Cosa ha in piu'in C++ a basso livello. 3 * 4 */ 5 6/* 7 * FUNZIONI INLINE: come si sarebbe fatto in C 8 * 9 */ 10 11// FUNZIONE versione 1 (tra interi) 12// Se la funzione come in questo caso e' molto semplice, il tempo 13// perso a fare la chiamata e' paragonabile se non superiore 14// al tempo di esecuzione della routine stessa. 15extern 16int 17funzione( int a, int b ); 18 19// FUNZIONE versione 2 (tra interi) 20// per evitare la chiamata alla funzione, uso la direttiva inline 21// in questo modo la funzione somma_inline non viene "richiamata" 22// ma "espansa" nel punto di chiamata 23 24inline // dichiaro la funzione come "inline" 25int 26funzione_inline( int a, int b ) { 27 int c = a-b ; 28 return c*c ; 29} 30 31/* 32 * Nel C non esistono le funzione inline, si usano le MACRO, 33 * occhio pero' che si possono fare degli errori 34 */ 35 36#define FUNZIONE_INLINE(A,B) (A-B)*(A-B) 37 38/* 39 * Fatta in questo modo e' sbagliata, infatti se la uso nel 40 * seguente modo: 41 * 42 * int c = FUNZIONE_INLINE( a-3, b+2 ) 43 * 44 * espansa diventa 45 * 46 * int c = ( a-3 - b+2 )*( a-3 - b+2 ); 47 * 48 * che e' diverso da 49 * 50 * int c = ( (a-3) - (b+2) )*( (a-3) - (b+2) ); 51 * 52 * come uno in realta' avrebbe inteso. 53 */ 54 55/* soluzione "alla C", uso delle parentesi */ 56 57#define FUNZIONE_INLINE_CORRETTA(A,B) ((A)-(B))*((A)-(B)) 58 59/* 60 * Fatta in questo modo e' corretta, infatti 61 * 62 * int c = FUNZIONE_INLINE( a-3, b+2 ) 63 * 64 * espansa diventa 65 * 66 * int c = ( (a-3) - (b+2) )*( (a-3) - (b+2) ); 67 * 68 */ 69 70/* 71 * PROBLEMI E LIMITAZIONI 72 * 73 * 1) le macro non permettono la defizione di funzioni complicate 74 * se non con trucchi complicato e comunque solo fino ad un certo 75 * punto 76 * 2) Nelle macro non si possono definire raccoglimenti o altro, ma 77 * questo compito viene demandato all'ottimizzatore. 78 * 79 */ 80 81 82/* 83 * Conclusione: quando possibile al posto delle MACRO usare le funzioni 84 * inline 85 * 86 */
-
Passaggio di parametri, uso delle reference
File ex005.cc
1/* 2 * Cosa ha in piu'in C++ a basso livello. 3 * 4 */ 5 6/* 7 * REFERENCE: ovvero puntatori "nascosti" 8 * 9 */ 10 11/* 12 * Esempio: 13 * voglio fare una subrutine che modifica un suo argomento. 14 * Ad esempio voglio calcolare sqrt(aromento+2) 15 */ 16 17#include <cmath> // includo le definizioni delle funzioni matematiche sin, cos, etc,. 18#include <iostream> // includo le definizioni per I/O in c++ 19 20using namespace std ; 21// le definizioni dell'I/O sono contenute in un namespace di nome std. 22// per estrarre tutto il contenuto del namespace std si usa l'istruzione 23// scritta sopra. 24// Se non uso "using namespace std" per accedere a cout dovrei usare 25// l'operatore di scope :: in questo modo std::cout 26 27void 28esempio_stupido_errato( double a ) { 29 a = sqrt(a+2) ; 30} 31 32int 33main() { 34 double a = 3 ; 35 esempio_stupido_errato( a ) ; 36 cout << "risultato = " << a << "\n" ; 37 38 // cout e' oggetto per I/O 39 // cout = character outout 40 // << operatore di output 41 // OGGETTO I/O << quello da sparare fuori 42 // ==> restituisce OGGETTO I/O e quindi posso usare ancora << 43 // 44 // Di fatti una cosa del tipo 45 // 46 // cout << a << b << c ; 47 // si deve interpretare come 48 // 49 // ((cout << a) << b) << c ; 50 // o meglio 51 // cout << a ; 52 // cout << b ; 53 // cout << c ; 54 // 55 // ad esempio 56 // cout << "risultato = " << a << "\n" ; 57 // e' equivalente a 58 // cout << "risultato = " ; 59 // cout << a ; 60 // cout << "\n" ; 61 62 63 // posso richiamarlo con l'argomento errato 64 esempio_stupido_errato( 2 ) ; // promozione del 2 da intero a double 65 66 return 0 ; 67} 68 69/* 70 * per compilare questo esempio bisogna usare la libreria 71 * standard del c++ che contiene ad esempio l'I/O come segue: 72 * 73 * gcc -Wall ex005.cc -lstdc++ 74 */
File ex006.cc
1/* 2 * Cosa ha in piu'in C++ a basso livello. 3 * 4 */ 5 6/* 7 * REFERENCE: ovvero puntatori "nascosti" 8 * 9 */ 10 11/* 12 * Esempio: 13 * voglio fare una subrutine che modifica un suo argomento. 14 * Ad esempio voglio calcolare sqrt(aromento+2) 15 */ 16 17#include <cmath> // includo le definizioni delle funzioni matematiche sin, cos, etc,. 18#include <iostream> // includo le definizioni per I/O in c++ 19 20using namespace std ; 21// le definizioni dell'I/O sono contenute in un namespace di nome std. 22// per estrarre tutto il contenuto del namespace std si usa l'istruzione 23// scritta sopra. 24// Se non uso "using namespace std" per accedere a cout dovrei usare 25// l'operatore di scope :: in questo modo std::cout 26 27void 28esempio_stupido_giusto( double * a ) { // per modificare il contenuto 29 // di "a" gli devo passare il suo indirizzo! 30 *a = sqrt(*a+2) ; 31} 32 33int 34main() { 35 double a = 3 ; 36 esempio_stupido_giusto( & a ) ; // operatore & serve per estrarre l'indirizzo 37 cout << "risultato = " << a << "\n" ; 38 39 // cout e' oggetto per I/O 40 // cout = character outout 41 // << operatore di output 42 // OGGETTO I/O << quello da sparare fuori 43 // ==> restituisce OGGETTO I/O e quindi posso usare ancora << 44 // 45 // Di fatti una cosa del tipo 46 // 47 // cout << a << b << c ; 48 // si deve interpretare come 49 // 50 // ((cout << a) << b) << c ; 51 // o meglio 52 // cout << a ; 53 // cout << b ; 54 // cout << c ; 55 // 56 // ad esempio 57 // cout << "risultato = " << a << "\n" ; 58 // e' equivalente a 59 // cout << "risultato = " ; 60 // cout << a ; 61 // cout << "\n" ; 62 return 0 ; 63} 64 65/* 66 * per compilare questo esempio bisogna usare la libreria 67 * standard del c++ che contiene ad esempio l'I/O come segue: 68 * 69 * gcc -Wall ex005.cc -lstdc++ 70 */
File ex007.cc
1/* 2 * Cosa ha in piu'in C++ a basso livello. 3 * 4 */ 5 6/* 7 * REFERENCE: ovvero puntatori "nascosti" 8 * 9 */ 10 11/* 12 * Esempio: 13 * voglio fare una subrutine che modifica un suo argomento. 14 * Ad esempio voglio calcolare sqrt(aromento+2) 15 */ 16 17#include <cmath> // includo le definizioni delle funzioni matematiche sin, cos, etc,. 18#include <iostream> // includo le definizioni per I/O in c++ 19 20using namespace std ; 21// le definizioni dell'I/O sono contenute in un namespace di nome std. 22// per estrarre tutto il contenuto del namespace std si usa l'istruzione 23// scritta sopra. 24// Se non uso "using namespace std" per accedere a cout dovrei usare 25// l'operatore di scope :: in questo modo std::cout 26 27void 28esempio_stupido_modo_cpp( double & a ) { // per modificare il contenuto 29 // di "a" gli devo passare il suo indirizzo! 30 // non lo passo tramite un puntatore 31 // ma tramite un riferimento. 32 // La sintassi usa & 33 a = sqrt(a+2) ; 34 // Di fatto a e' un puntatore ma quando lo uso faccio 35 // riferimeno al suo contenuto. Di fatto e' un ALIAS (sinonimo) 36 // della variabile passata. 37} 38 39int 40main() { 41 double a = 3 ; 42 esempio_stupido_modo_cpp( a ) ; 43 cout << "risultato = " << a << "\n" ; 44 45 // cout e' oggetto per I/O 46 // cout = character outout 47 // << operatore di output 48 // OGGETTO I/O << quello da sparare fuori 49 // ==> restituisce OGGETTO I/O e quindi posso usare ancora << 50 // 51 // Di fatti una cosa del tipo 52 // 53 // cout << a << b << c ; 54 // si deve interpretare come 55 // 56 // ((cout << a) << b) << c ; 57 // o meglio 58 // cout << a ; 59 // cout << b ; 60 // cout << c ; 61 // 62 // ad esempio 63 // cout << "risultato = " << a << "\n" ; 64 // e' equivalente a 65 // cout << "risultato = " ; 66 // cout << a ; 67 // cout << "\n" ; 68 69 float b = 2 ; 70 esempio_stupido_modo_cpp( b ) ; // errore non esiste promozione nei riferimenti 71 72 esempio_stupido_modo_cpp( 2.0 ) ; // errore 2.0 e' una costante e non puo' essere 73 // modificata 74 return 0 ; 75} 76 77/* 78 * per compilare questo esempio bisogna usare la libreria 79 * standard del c++ che contiene ad esempio l'I/O come segue: 80 * 81 * gcc -Wall ex005.cc -lstdc++ 82 */
-
Uso delle reference per sezionare le strutture
File ex008.cc
1/* 2 * Cosa ha in piu'in C++ a basso livello. 3 * 4 */ 5 6/* 7 * REFERENCE: ovvero puntatori "nascosti" 8 * 9 */ 10 11/* 12 * Esempio: 13 * Uso delle reference per accedere a strutture complesse 14 */ 15 16#include <cmath> // includo le definizioni delle funzioni matematiche sin, cos, etc,. 17#include <iostream> // includo le definizioni per I/O in c++ 18 19using namespace std ; 20// le definizioni dell'I/O sono contenute in un namespace di nome std. 21// per estrarre tutto il contenuto del namespace std si usa l'istruzione 22// scritta sopra. 23// Se non uso "using namespace std" per accedere a cout dovrei usare 24// l'operatore di scope :: in questo modo std::cout 25 26 27// definisco una stuttura complicata 28 29typedef struct { 30 double a, b, c ; 31} struct1 ; 32 33typedef struct { 34 struct1 sa, sb ; 35 int ia, ib, ic ; 36} struct2 ; 37 38typedef struct { 39 struct1 s1 ; 40 struct2 s2 ; 41} struct3 ; 42 43/* 44 * +-------------+ 45 * | s1----+ | 46 * | | a | | 47 * | +-----+ | 48 * | | b | | 49 * | +-----+ | 50 * | | c | | 51 * | +-----+ | 52 * | s2--------+ | 53 * | | sa----+ | | 54 * | | | a | | | 55 * | | +-----+ | | 56 * | | | b | | | 57 * | | +-----+ | | 58 * | | | c | | | 59 * | | +-----+ | | 60 * | | sb----+ | | 61 * | | | a | | | <---- 62 * | | +-----+ | | | 63 * | | | b | | | <---- nel prossimo esempio accedo a questi campi 64 * | | +-----+ | | | 65 * | | | c | | | <---- 66 * | | +-----+ | | 67 * | | +-----+ | | 68 * | | | ia | | | 69 * | | +-----+ | | 70 * | | | ib | | | 71 * | | +-----+ | | 72 * | | | ic | | | 73 * | | +-----+ | | 74 * | +---------+ | 75 * +-------------+ 76 * 77 * Stuttura tipo struct2 78 * / \ 79 * s1 s2--------------- 80 * / | \ / \ \ \ \ 81 * a b c sa sb ia ib ic 82 * / | \ / | \ 83 * a b c a b c 84 */ 85 86void 87accedi_a_sb( struct3 & s ) { 88 s.s2.sb.a = 1 ; 89 s.s2.sb.b = 2 ; 90 s.s2.sb.c = 3 ; 91} 92 93void 94accedi_a_sb_migliorato( struct3 & s ) { 95 // uso un riferimento per accedere alla sottostruttura 96 struct1 & sb_ref = s.s2.sb ; 97 sb_ref.a = 1 ; 98 sb_ref.b = 2 ; 99 sb_ref.c = 3 ; 100 101 // avrei potuto usare anche un puntatore come segue 102 struct1 * sb_ptr = & s.s2.sb ; 103 104 (*sb_ptr).a = 1 ; // modo 1 105 (*sb_ptr).b = 2 ; 106 (*sb_ptr).c = 3 ; 107 108 sb_ptr -> a = 1 ; // con l'operatore -> e' piu leggibile 109 sb_ptr -> b = 2 ; 110 sb_ptr -> c = 3 ; 111}
File ex008.cc
1/* 2 * Cosa ha in piu'in C++ a basso livello. 3 * 4 */ 5 6/* 7 * CONST: ovvero la dichiarazione delle costanti 8 * 9 */ 10 11/* 12 * Esempio: 13 * Uso delle reference per accedere a strutture complesse 14 */ 15 16#include <cmath> // includo le definizioni delle funzioni matematiche sin, cos, etc,. 17#include <iostream> // includo le definizioni per I/O in c++ 18 19using namespace std ; 20// le definizioni dell'I/O sono contenute in un namespace di nome std. 21// per estrarre tutto il contenuto del namespace std si usa l'istruzione 22// scritta sopra. 23// Se non uso "using namespace std" per accedere a cout dovrei usare 24// l'operatore di scope :: in questo modo std::cout 25 26 27// definisco una stuttura complicata 28 29typedef struct { 30 double a, b, c ; 31} struct1 ; 32 33typedef struct { 34 struct1 sa, sb ; 35 int ia, ib, ic ; 36} struct2 ; 37 38typedef struct { 39 struct1 s1 ; 40 struct2 s2 ; 41} struct3 ; 42 43/* 44 * +-------------+ 45 * | s1----+ | 46 * | | a | | 47 * | +-----+ | 48 * | | b | | 49 * | +-----+ | 50 * | | c | | 51 * | +-----+ | 52 * | s2--------+ | 53 * | | sa----+ | | 54 * | | | a | | | 55 * | | +-----+ | | 56 * | | | b | | | 57 * | | +-----+ | | 58 * | | | c | | | 59 * | | +-----+ | | 60 * | | sb----+ | | 61 * | | | a | | | <---- 62 * | | +-----+ | | | 63 * | | | b | | | <---- nel prossimo esempio accedo a questi campi 64 * | | +-----+ | | | 65 * | | | c | | | <---- 66 * | | +-----+ | | 67 * | | +-----+ | | 68 * | | | ia | | | 69 * | | +-----+ | | 70 * | | | ib | | | 71 * | | +-----+ | | 72 * | | | ic | | | 73 * | | +-----+ | | 74 * | +---------+ | 75 * +-------------+ 76 * 77 * Stuttura tipo struct2 78 * / \ 79 * s1 s2--------------- 80 * / | \ / \ \ \ \ 81 * a b c sa sb ia ib ic 82 * / | \ / | \ 83 * a b c a b c 84 */ 85 86void 87accedi_a_sb( struct3 const & s ) { 88 s.s2.sb.a = 1 ; // errore non posso modicare una struttura dichiata costante 89 s.s2.sb.b = 2 ; 90 s.s2.sb.c = 3 ; 91} 92 93/* 94 * Il const fa riferimento alla "cosa" alla sua sinistra 95 * a meno che non sia la prima parola nella definizione. 96 * Esempi: 97 98 const int a = 1 ; // a e' una variabile di tipo intero 99 // a valore 1 e non e' modifocabile 100 int const a = 1 ; // equivalente, preferito da me. 101 int const a ; // non ha senso perche' a non e' inizializzata e 102 // non e' modificabile. 103 104 105 int const * pa ; // pa e' un puntatore (che si puo' modificare) 106 // ad un intero non modificabile 107 108 pa = & a ; // istruzione valida 109 *pa = 1 ; // errore *pa non si puo' modificare 110 111 int b ; 112 int * const pb = & b ; // il puntatore stesso non e' modificabile 113 // ma quello a cui punta si. 114 *pb = 3 ; // istruzione valida 115 ++pb ; // Istruzione NON VALIDA pb non si puo modificare 116 // pb e' "quasi" un riferimento. 117 118 int const * const pc = & b ; // puntatore constante a un intero non 119 // modificabile. 120 121 int d = *pc ; // istruzione valida 122 --pc ; // No, pc non e' modificabile 123 (*pc)++ ; // No, quello a cui punta pc non e' modificavile 124 125 126 int & c = d ; // riferimento alla variabile d 127 int & e = a ; // non e' valido perche a e' una variabile costante 128 // mentre il riferimento non lo e'! 129 int const & f = a ; // cosi e' valido. 130 131 132 */