Vocabolario C++

44
Vocabolario C++ Sommario 000. Commenti 001. Un semplice programma 002. Tipi di dati 002.1 Qualificatori 002.2 Operatore sizeof() 003. Definzione di una varibile 004. Assegnazione 005. Input/Output 006. Costanti 007. Tipi enumerati (enum) 008. Casting (Arrotondamento int/double) 009. Operatori aritmetici 010. Funzioni matematiche ( #include <cmath> ) 011. Operatori di confronto o logici 012. Funzioni relative alle stringhe 013. If-Else 014. Operatore ternario o di selezione 015. While - Do While - For 016. Funzioni 017. Procedure 018. Parametri passati per valore e per riferimento 019. Array 020. Array multidimendionali 021. Strutture (costrutto struct) 022. Classi La sintassi Le istanze Incapsulamento dei dati Definizione di una funzione membro Definizione di un costruttore Classi e funzioni esterne Overloading degli operatori Ereditarietà e Polimorfismo 023. Vettori (costrutto vector) 024. Puntatori Memoria statica e memoria dinamica Sintassi Deriferimento e accesso Array e puntatori //============================================================//

Transcript of Vocabolario C++

Page 1: Vocabolario C++

Vocabolario C++Sommario

000. Commenti001. Un semplice programma002. Tipi di dati

002.1 Qualificatori002.2 Operatore sizeof()

003. Definzione di una varibile004. Assegnazione005. Input/Output006. Costanti007. Tipi enumerati (enum)008. Casting (Arrotondamento int/double)009. Operatori aritmetici010. Funzioni matematiche ( #include <cmath> )011. Operatori di confronto o logici012. Funzioni relative alle stringhe013. If-Else014. Operatore ternario o di selezione015. While - Do While - For016. Funzioni017. Procedure018. Parametri passati per valore e per riferimento019. Array020. Array multidimendionali021. Strutture (costrutto struct)022. Classi

La sintassiLe istanzeIncapsulamento dei datiDefinizione di una funzione membroDefinizione di un costruttoreClassi e funzioni esterneOverloading degli operatoriEreditarietà e Polimorfismo

023. Vettori (costrutto vector)024. Puntatori

Memoria statica e memoria dinamicaSintassiDeriferimento e accessoArray e puntatori

//============================================================//

Page 2: Vocabolario C++

000. Commenti

/* commento */ //commento

//============================================================//

Page 3: Vocabolario C++

001. Un semplice programma:

#include <iostream> // inclusione del file header che contiene funzioni e operatori per la gestione degli strem di input/outputusing namespace std; // i nomi utilizzati nel programma appartengono al namespace standard

int main() // funzione principale del programma (int perchè il programma restituirà un intero alla fine dell'esecuzione){ // le istruzioni del corpo della funzione main sono racchiuse in due parentesi graffe cout << "Hello, World!\n"; // ogni istruzione termina con un punto e virgola; cout invia alla periferica di output la stringa "Hello, World!\n" ; \n manda a capo return 0; // alla fine dell'esecuzione il programma restituisce un valore intero 0}

//============================================================//

Page 4: Vocabolario C++

002. Tipi di dati Int Numero intero 2 byte (16 bit) Short Numero intero "corto" 2 byte (16 bit) Long Numero intero "lungo" 4 byte (32 bit) Float Numero reale 4 byte (32 bit) Double Numero reale "lungo" 8 byte (64 bit) String Sequenza di caratteri

//============================================================//

002.1 Qualificatori

signed ......... solo per char e int

unsigned ....... solo per char e int

short .......... solo agli int

long ........... solo a int e double

//============================================================//

002.1 Operatore sizeof()

sizeof( <tipo_dati> ) // restituisce lo spazio in memoria occupato da una varibile del tipo indicato

sizeof(int) // restituisce 2 cioè 2 byte ossia 16 bit ossia 2^16 numeri

//============================================================//

Page 5: Vocabolario C++

003. Definizione di una variabile

nome_tipo nome_variabile;

int numero; // definizione di una varibile di tipo intdouble pi_greco; // definzione della varibile pi greco di tipo doublestring nome; // def. della stringa di caratteri nome

//============================================================//

Page 6: Vocabolario C++

004. Assegnazione

variabile = espressione;

nomero = 1204; // assegnazione di un valore ad una costante intnome = "NurAbSal"; // assegnazione di un'espressione ad una stringa. l'espressione è contenuta all'interno di due doppi apici " " double = 3.14; // assegnazione di un numero a virgola mobile

una variabile puo' essere assegnata anche nel momento della definizione:

int numero = 12340;string nome = "Francesco";

//============================================================//

Page 7: Vocabolario C++

005. Istruzioni di Input/Output

005.1 output

cout << espressione;cout << espressione1 << espressione2 << espressione3;

cout << "Il tuo nome e' " << nome; // le stringhe sono sempre contenute all'interno dei doppi apicicout << "Il numero scelto e' " << numero << "\n"; // \n serve per andare a capo

//============================================================//

005.2 input

cin >> variabile;cin >> variabile1 >> varibile2 >> variabile3;

cin >> numero; // legge il valore di numero in inputcin >> nome >> cognome; // legge il valore di piu' varibili in input

//============================================================//

Page 8: Vocabolario C++

006. Costanti

const nome_tipo nome_costante = valore;

const int giorni_dell_anno = 365; // definizione di una costante. una costante mantiene il suo valore per tutta l'esecuzione del programma

//============================================================//

Page 9: Vocabolario C++

007. Tipi enumerati (enum)

enum settimana { lunedi, martedi, mercoledi, giovedi, venerdi, sabato, domenica }

in questo modo 'settimana' diventa un 'tipo' come int e come string e si possono dichiarare variabili di quesl tipo

settimana giorno_riposo = domenica; // definisco una varibile di tipo settimana e le assegno l'espressione domenica

//============================================================//

Page 10: Vocabolario C++

008. Casting (Arrotondamento int/double)

double virgola = 23.68;int intero = virgola; // intero vale 23 perde tutti i dati dopo la virgolaint approssimato = static_cast<int>(virgola + 0.5); // approssimato vale 24, in questo modo viene approssimato il numero a virgola mobile

casting:

(< Nuovo_Tipo >)<valore> es. (float)a< Nuovo_Tipo >(<valore>) es. float(a)

//============================================================//

Page 11: Vocabolario C++

009. Operatori aritmetici

Operazioni con gli int Simbolo Esempio

Addizione + 4 + 27 = 31 Sottrazione - 76 - 23 = 53 Moltiplicazione * 4 * 7 = 28 Divisione intera / 10 / 3 = 3

(3 è il n di volte divisibili senza resto) Divisione con modulo % 11 / 6 = 5

(5 è il resto della divisione)

x++; equivale a x = x + 1;y--; equivale a y = y - 1;

Operazioni con i double Simbolo Esempio

Addizione + 2.5 + 14.3 = 16.8 Sottrazione - 43.8 - 12.7 = 31.1 Moltiplicazione * 7.5 * 3.0 = 22.5 Divisione / 5.0 / 2.0 = 2.5

//============================================================//

Page 12: Vocabolario C++

010. Funzioni matematiche ( #include <cmath> )

richiedono varibili di tipo double o float

sin(x) exp(x) esponenziale con base e sqrt(x) radice quadrata di xcos(x) log(x) logaritmo naturale pow(x, y) x^ytan(x) log10(x) log. in base dieciasin(x) fabs(x) valore assolutoacos(x) floor(x) intero più grande minore o uguale di xatan(x) ceil(x) intero più piccolo maggiore o uguale di x

//============================================================//

Page 13: Vocabolario C++

011. Operatori di confronto e logici

Simbolo Significato Utilizzo == uguale a a == b != diverso da a != b < minore a < b > maggiore a > b <= minore o uguale a <= b >= maggiore o uguale a >= b

Simbolo Significato Utilizzo

&& AND logico a && b || OR logico a || b

//============================================================//

Page 14: Vocabolario C++

012. Funzioni relative alle stringhe

string name = "nurabsal";int lunghezza_nome = name.length(); / assegno alla variabile di tipo int la lunghezza della stringa name

string pezzo;pezzo = name.substr(0, 3); / assegno alla stringa pezzo la sottostringa ottenuta da name a partire dal primo carattere (indice 0) di lunghezza 3 cioè 'nur'

getline(cin, name); /legge la stringa name dall'input cin (questa istruzione permette di inserire spazi nella lettura dell'input)

//============================================================//

Page 15: Vocabolario C++

013. If-Else

if (condizione) // se la condizione è verificata esegue l'istruzione istruzione

if (condizione) // se la condizione è verificata esegue le istruzioni contenute nel blocco compreso tra le parentesi graffe { istruzione1; istruzione2; }

if (condizione) // se la condizione è verificata esegue l'istruzione1 istruzione1else // altrimenti esegue l'istruzione2 istruzione2

if (condizione1) // else if concatenato che permette di verificare più condizioni istruzione1else if (condizione2) istruzione2else istruzione3

//============================================================//

Page 16: Vocabolario C++

014. Operatore ternario o di selezione

// Operatore ternario ?test ? espressione2 : espressione3

// Corrispondente blocco if-elseif (test){ espressione2} else { espressione3

}

if (alfa > beta) max = alfa;else max = beta;

// che corrisponde a...max = (alfa>beta) ? alfa : beta

//============================================================//

Page 17: Vocabolario C++

015. While - Do While - For

while (condizione) istruzione/i // esegue l'istruzione finchè la condizione rimane vera

ESEMPIO:

int sentinella, x, temp = 1;cin << x;

while ( sentinella <= x ) // algoritmo del fattoriale di x{fattoriale = fattoriale * sentinella;sentinella++;}

//============================================================//

do istruzione/i // come il while solo che esegue almeno una volta l'istruzionewhile (condizione) // esegue l'istruzione almeno una volta e poi la ripete finchè rimane vera la condizione

//============================================================//

for (inizializzazione ; condizione ; incremento) istruzione/i

ESEMPIO:

int sentinella, a, temp = 1;cin << a;

for (sentinella = 1; sentinella <= a; sentinella++) // algoritmo del fattoriale

Page 18: Vocabolario C++

{temp = temp * sentinella;}

che equivale alla rappresentazione con un while con la seguente struttura: inizializzazionewhile (condizione) istruzione/i incremento

//============================================================//

Page 19: Vocabolario C++

016. Funzioni

Dichiarazione:

tipo_restituito nome_funzione (parametro1, parametro2, ...., parametroN);

es. int modulo(x);

// una funzione va dichiarata all'inizio prima del main

//============================================================//

Definizione:

// una funzione va definita all'inizio del programma prima del main o alla fine// se la si definisce all'inizio non servirà fare il passaggio precedente della dichiarazione poichè la definizione contiene già la dichiarazione

tipo_restituito nome_funzione (parametro1, parametro2, ...., parametroN){

istruzioni}

es. double modulo(double x); { if (x >= 0) return x; else return -x; }

es.int fattoriale( int a ) {int sentinella, temp = 1; for (sentinella = 1; sentinella <= a; sentinella++){temp = temp * sentinella;}return temp;}

Page 20: Vocabolario C++

//============================================================//

Invocazione funzione

main() {

...int variabile = fattoriale(4); // 4 viene detto parametro attuale, a variabile viene assegnato il valore 4!cout << variabile; // viene stampato a schermo: 24...

}

//============================================================//

Page 21: Vocabolario C++

017. Procedure

Dichiarazionevoid <nome_procedura>(<parametri>);

Definizionevoid <nome_procedura>(<parametri>){...}

Una procedura è una funzione che non restituisce nessun valore. Puo' essere invocata come un istruzione senzadover utilizzare una variabile, proprio perchè non assume nessun valore. (void = nulla)

Esempio:

void paro_o_caffo(int n){if ( (n%2) == 0 ) cout << n << " e' paro";else cout << n << " e' caffo";}

int main(){int numero = 5;

paro_o_caffo(numero); // verrà stampato da cout a schermo: '5 e' caffo'

}

//============================================================//

Page 22: Vocabolario C++

018. Parametri passati per valore e per riferimento

void paro_o_caffo(int n){ ... }

int modulo(int x){ return( x >= 0 ? x : -x );}

n e x qui sopra sono parametri formali, ossia hanno una funzione formale all'interno della definizione della funzione o della procedura

main() {...int numero = 2, numero2 = 3;y = modulo(numero);paro_o_caffo(numero2);...}

numero e numero2 sono detti parametri attuali poichè sono i parametri con cui viene attualizzata la funzione o procedurauna volta invocata la funzione il ruolo del parametro formale viene attualizzato dal parametro attuale con il quale è stata invocata

nei casi precedenti si parla di parametri passati per valore, ossia la funzione prende il lettura i parametri attuali ma non compie modifiche su di loro. una funzione restituirà un valore presumibilmente a seconda del valore del parametro attuale ma quest'ultimo non subirà modifiche. anche per le procedura vale questa cosa con i parametri passati per valore. affichè non sia inutile una procedura con parametri per valore questa eseguirà delle istruzioni a seconda del valore per parametro attuale senza modificarlo

esempio:

void abs(int n){if (n < 0) n = -n;}

questa procedura e' del tutto inutile poichè il parametro formale n è un poarametro passato per valore che non viene modificato dalla procedura nella sua invocazione. per modificare un parametro con il quale viene invocata una procedura o una funzione si debbono usare i parametri per riferimento.

Page 23: Vocabolario C++

esempio

void abs(int& n){if (n < 0) n = -n;}

questa procedura ha un parametro n passato per riferimento. questo significa che ogni modifica che subirà il parametro formale nella ddefinizione della procedura si ripercuoterà sulla variabile con la quale è stata attualizzata la procedura

int numero=-2;abs(numero);//ora numero vale 2

i parametri attuali passati per riferimento possono essere solo variabili e non espressioni (numeri, espressioni matematiche)

i parametri passati per valore (in lettura) consistono in una copia del parametro attuale, una volta conclusa l'attivazione della funzione viene cancellata questa copia

i parametri passati per riferimento consistono nell'inidirizzo della cella di memoria contenente il parametro attuale con il quale è stata attivata la funzione o procedura. quindi le modifiche vengono a ripecuotersi direttamente ed immediatamente durante l'attivazione sul parametro attuale

//============================================================//

Page 24: Vocabolario C++

019. Array

Gli array sono dei tipi di dati 'vettori' che contengono una serie composta da un certo numero fissato di variabili di tipo omogeneo, tutti int o tutti double ecc...Un array di interi si definisce così:

int vettore[100]; // questo vettore contiene 100 elementi int

o meglio:

const int dim = 100;int vettore[dim]; //la dimensione deve essere sempre una costante intera

L'ordinamento di un array di N elementi è organizzato in modo che il primo elemento dell'array abbia indice 0 (e NON 1) e che l'ultimo elemento abbia quindi indice N-1.

per puntare all'elemento i-esimo dell'array:array[i] = 2;

per scandire un vettore:for(int i=0;i<dim;i++) array[i]=0; //imposta a zero i valori di un array

Gli array vengono passati alle funzioni o procedure sempre per riferimento per questioni di velocità di calcolo. Non è quindi necessario indicare nel prototipo (dichiarazione) e nella definizione della funzione tramite il simbolo '&' che la variabile array che viene passata come parametro alla funzione è per rifermento. Inoltre un array non puo' mai essere restituito da una funzione. Questo problema si aggira infatti tramite il passaggio per riferimento (obbligato) di un array ad una funzione.

void imposta(int array[], int valore, int dim) { //senza indicare la dimensione del vettore nella dichiarazione si estende

//l'utilizzo della funzione per ogni generico vettore che verrà scandito

//fino all'elemento dim-1 (passando come param. in lett. un 'int dim'

for(int i=0;i<dim;i++) array[i]=valore;

}

Se si vuole esser certi che un vettore non venga modificato da una funzione si utilizza la parola 'const'

void vedi(const int array[], int dim) {for(int i=0;i<dim;i++) cout << array[i] << endl;

Page 25: Vocabolario C++

}

Chiamate corrette delle procedure di cui sopra:

vedi(array, dim);imposta(array, 120, dim);

//============================================================//

Page 26: Vocabolario C++

020. Array multidimendionali

const int R = 20 ;const int C = 30 ;

double matrice[R][C];

Possono essere definiti array multidimensionali, per rappresentare ad esempio una matrice. Vengono utilizzati due indici di cui il primo indica sempre il numero di righe ed il secndo sempre il numero di colonne. Nel passaggio ad una funzione di un array multidimensionale il secondo indice, o indice delle colonne va sempre specificato e non puo' essere omesso come nell'array unidimensionali.

void stampa(double matrice[R][C], int r, int c); oppurevoid stampa(double matrice[][C], int r, int c);

ma non: // void stampa(double matrice[][], int r, int c); SCORRETTO!!!

Chiamata corretta della funzione:

stampa(matrice, 10, 5);

Funzione che stampa solo i valori significativi di un array bidimensionale.

void stampa(double matrice[R][C], int r, int c) {

for (int i=0; i<r; i++) { cout << endl; for (int j=0; j<c; j++)

cout << matrice[i][j] << " "; }

//============================================================//

Page 27: Vocabolario C++

021. Strutture (costrutto struct)

Strutture

Le strutture permettono un'aggregazione di variabili, molto simile a quella degli array, ma a differenza di questi non ordinata e non omogenea (una struttura può contenere variabili di tipo diverso). Per denotare una struttura si usa la parola chiave struct seguita dal nome identificativo della struttura, che è opzionale. Nell'esempio sottostante si definisce una struttura "libro" e si crea una variabile di essa chiamata "biblio":

// dichiarazione della structstruct libro { char titolo[100];

char autore[50]; int anno_pubblicazione;

float prezzo; };

//dichiarazione dell'istanza bibliostruct libro biblio;

//o anchelibro biblio;

La variabile "biblio" può essere dichiarata anche mettendo il nome stesso dopo la parentesi graffa:

// dichiarazione della struct e della variabile biblio

struct libro { char titolo[100];

char autore[50]; int anno_pubblicazione;

float prezzo; } biblio;

mentre è possibile pre-inizializzare i valori, alla dichiarazione, mettendo i valori (giusti nel tipo) compresi tra parentesi graffe:

Page 28: Vocabolario C++

struct libro biblio = {"Guida al C", "Fabrizio Ciacchi", 2003, 45.2};

// o anche

libro biblio = {"Guida al C", "Fabrizio Ciacchi", 2003, 45.2};

Per accedere alle variabili interne della struttura si usa l'operatore "."; una volta che si può accedere ad una variabile interna questa può essere trattata e/o manipolata come qualsiasi altra variabile:

// assegna un valore al prezzo del librobiblio.prezzo = 67.32;

// assegna ad una variabile int l'anno di pubblicazione del libroint anno = biblio.anno_pubblicazione;

// stampa il titolo del librocout << biblio.titolo;

Page 29: Vocabolario C++

022. Classi

La programmazione ad oggetti si basa sulle classi. Le classi sono oggetti che comprendono campi dati e funzioni membro proprie dell’oggetto.

La sintassi:

class nome_classe {public:

funzioni membro o metodiprivate:

dati};

Le funzioni, che si chiamano anche metodi, si dividono in costruttori, funzioni di accesso, e funzioni di mutazione.I campi dati possono essere occupati da tipi di dati fondamentali, array, o altre classi anche.

Esempio:

class complesso {public:

complesso();complesso(double x);complesso(double x, double y); //costruttori

double re() const ;double im() const; //funzioni di accesso

sum(double x, double y) ; //funzioni di mutazioneprivate:

double real;double imag;

};

I dati vengono preferibilimente inseriti tra i dati privati. Questi quindi sono accedibili solo dalle funzioni membro proprie della classe.

//============================================================//

Le istanze Le istanze di una classe si dichiarano in questo modo:

complesso x1;complesso x2(4.5, 3);

Vengono utilizzati i due costruttori, nel primo caso quello di default che viene sempre usato quando un oggetto viene dichiarato senza parametri, e nel secondo caso il costruttore con l’esatto numero di paramentri specificati nella dichiarazione. Questo si chiama overloading dei costruttori.

Page 30: Vocabolario C++

Un oggetto puo’ essere reinizializzato utilizzando uno dei costruttori:

x1 = complesso(1, 2);x2 = complesso();

Ma non si puo’ ripetere una dichiarazione come:

complesso x1;complesso x1(2, 4); //ERRORE

//============================================================//

Incapsulamento dei datiNon sono visibili dall’esterno i campi dati impostati come ‘private’ e’ quindi scorretto:

double parte_reale = x1.real; //ERRORE

ma va usata una funzione membro per accedere ai campi dato

double parte_reale = x1.re();

//============================================================//

Definizione di una funzione membro:

tipo_restituito nome_classe::nome_funzione( … parametri … ) [const] //se funz.di accesso{istruzioni}

Esempio:

double complesso::im() const {return imag;}

void complesso::sum(double x, double y) {imag = imag + y;real = real + x ;}

Page 31: Vocabolario C++

//============================================================//

Definizione di un costruttore.

Nome_classe::nome_classe( … parametri … ) {istruzioni}

Esempi

complesso::complesso() { } //costruttore di default, non vengono inizializzati i campi dato

oppure

complesso::complesso() { real=0; imag=0; }

ancora

complesso::complesso(double x, double y) { real=x ; imag=y ; }

Costruttore con elenco di inizializzazione dei campi

nome_classe::nome_classe(parametri): campo1 (espressione), .... , campoN (espressione) {istruzioni}

Esempio

complesso::complesso(double x, double y) : real(x), imag(y){}

//============================================================//

Page 32: Vocabolario C++

Classi e funzioni esterne

Le classi possono essere restituite da una funzione. Il passaggio delle classi come parametri alle funzioni di default è per valore. Il passaggio per riferimento va esplicitato con ‘&’. Per non appesantire la memoria si puo’ utilizzare un passaggio per riferimento con ‘&’ ed inoltre ‘const’ che assicura che i campi dato della classe non vengano modificati.

Esempi:

class complesso {public:

…complesso somma(const complesso& n) const;

private:…

};

//funzione membro che restituisce una classe complesso. complesso a, b, c;a = b.somma(c); //a=b ‘+’ c

Il primo (l’istanza b) si chiama parametro implicito, il secondo esplicito. Il parametro esplicito in questo caso viene passato per riferimento ma utilizzando la parola riservata ‘const’ non viene modificato dalla funzione. Il parametro implicito è sempre passato per riferimento. La funzione è di accesso e non modifica i campi dato della funzione, quindi alla fine c’è const.

Definizione di complesso::somma

complesso complesso::somma(const complesso& n) const {complesso result;double x, y;x = real + n.re() ;y = imag + n.im();result = complesso(x, y) ;return result ;}

//============================================================//

Overloading degli operatori.Possiamo ridefinire il significato degli operatori di base per una classe.

Page 33: Vocabolario C++

Esempi:

class complesso {public:

…bool operator==(complesso a);complesso operator+(complesso a);

private:…

};

Esempi di utilizzo:

complesso a, b;…if (a==b) { … }a = a + b;

Definizioni

bool complesso::operator==(complesso a) {return ( real==a.re() && imag==a.im() );}

complesso complesso::operator+(complesso a) {complesso result;double x, y;x = real + a.re() ;y = imag + a.im();result = complesso(x, y) ;return result ;}

Page 34: Vocabolario C++

Ereditarietà e PolimorfismoE’ possibile ampliare le calssi già esistenti grazie alla facoltà dell’ereditarietà delle classi. Vengono cosi ad esistere contestualmente una classe base, e una classe derivata, che eredita i metodi e i campi dati della classe base e puo’ eventualemente ed opportunamente estenderli, sostituirli, o ereditarli semplicemente.Tutte la funzioni membro e i membri dati della classe base vengono ereditati dalla classe derivata.

Sintassi:

class Nome_classe_derivata : public Nome_classe_base {

public:nuove f.ni membro

private:nuovi membri dati

};

Esempio:

class Employee{public:

Employee();Employee(string _name, double _salary);void set_salary(double new_salary);string get_name() const;double get_salary() const;

private:string name;double salary;

};

class Manager : public Employee{public:

Manager(string name, double salary, string dept);string get_department() const;

private:string department;

};

Page 35: Vocabolario C++

Se i campi dati della classe base sono ‘protected’, la classe derivata puo’ accedere direttamente ad essi tramite i propri metodi. Se invece sono dichiarati ‘private’ non sarà cio’ possibile e si dovrà ricorrere alle funzioni membro della classe base. Tuttavia si preferisce non utilizzare i dati protected ed accedere tramite la funzioni membro della classe base ai campi dati della classe base.

class nome_classe_base {protected: //invece che private:

dati...public:

metodi...};

I campi dati della classe base non sono visibili ai metodi delle classi derivate se dichiarati, come è buona norma, privati. Vanno utilizzati i metodi della classe base per modificarli.

class Manager : public Employee{public:

...void aumenta(double x)

private :...

} ;

void Manager::aumenta(double x) { //SCORRETTO salary=salary+x set_salary( get_salary() + x ); //viene intepretato param_implicito.set_salary( param_implicito.get_salary() + x ); }

Il che è equivalente a:

void Manager::aumenta(double x) { Employee::set_salary(Employee::get_salary()+x); }

In effetti quando viene chiamata la set_salary() senza esplicitare Employee::set_salary() viene chiamata la funzione mebro ereditata dalla classe base. In questo caso dato che il metodo viene semplicemente ereditato si puo' omettere il richiamo esplicito alla classe base. Non si puo' omettere invece questo richiamo se viene ampliata la funzione membro base da quella derivata.

class Employee{public:

...void print() const;

private:

Page 36: Vocabolario C++

...};

class Manager : public Employee{public:

...void print() const;

private :...

};

void Employee::print() const { cout<<"L'impiegato si chiama "<<name <<" e guadagna "<<salary; }

Manager::print() const { Employee::print(); cout<<" lavora nel dipartimento "<<department; }

Se nell'implementazione del metodo print() di Manager che amplia la print() di Employee si fosse usato semplicemente usata l'istruzione print(); sarebbe stata richiamata ricorsivamente la stessa funzione Manager::print() fino allo stack overflow.

Un procedimento analogo va effettuato nell’implementazione dei costruttori della classe derivata.Sintassi del costruttore della classe derivata con inizializzazione della classe base.

Nome_classe_derivata::Nome_classe_derivata(espressioni): Nome_classe_base(espressioni)

{istruzioni

}

Esempio:Manager::Manager(string name, double salary, string dept)

: Employee(name, salary){

department=dept;}

In questa maniera viene invocato prima di eseguire le istruzioni del costruttore della classe derivata, il costruttore della classe base con i parametri ‘name’ e ‘salary’ in questo caso. Nel caso in cui venga omesso questa chiamata del costruttore della classe base, verrà chiamato il costruttore di default della classe base.

Page 37: Vocabolario C++

Il polimorfismo consiste nella possibilità di creare un assortimento, tramite i vettori (vector) ad esempio, di oggetti di piu’ tipi. Una raccolta di questo tipo è definita polimorfica. Sarà possibile cioe’ disporre di un vettore di puntatori (*) ad oggetti di una classe base, che potranno puntare anche ad istanze di classi derivate di quella base.

Esempio:

vector<Employee*> staff(3);staff[0]=new Employee("francesco",2000);staff[1]=new Employee("simone",3000);staff[2]=new Manager("nello",4000,"colleverde");

In questa maniera la raccolta è polimorfica poichè vengono allocati sia oggetti della classe base che di quella derivata, il vettore che punta ai diversi oggetti è unico e contiene dei puntatori alla classe base. E' importante che siano dei puntatori alla classe base perchè sarebbe un errore utilizzare dei puntatori a classi derivate per cercare di accedere alle relative classi base.

Tuttavia essendo gli elementi del vettore dei puntatori alla classe base, quando verrà de-referenziato un puntatore ad un oggetto per utilizzare una funzione membro dell'oggetto, se le funzioni membro delle classi sono dichiarate in modo standard come fino ad ora visto, verrà chiamata la funzione membro della classe base anche se il puntatore punta ad un’istanza di una classe derivata. Non sarà così possibile accedere alle funzioni membro caratteristiche degli oggetti di classi derivate nè a quelle ampliate nè a quelle sostituite o modificate. L'utilizzo che se ne puo' fare degli oggetti derivati sarà il medesimo di quello degli oggetti di base, se la funzioni membro sono dichiarate nel modo classico.

Esiste un modo per gestire una raccolta di puntatori ad oggetti polimorfica in modo dinamico permettendo in runtime di scegliere la funzione membro relativa all'oggetto puntato e non solamente di quello base. Questa capacità è detta polimorfismo e la tecnica si chiama Binding Dinamico, la scelta cioe' in tempo reale, in modo dinamico delle funzioni membro dell'oggetto interessato. Si parla di Binding Statico nei casi precedenti, quando si sa già quale sarà la funzione da applicare all'oggetto che non viene scelta infatti in runtime. Per effettuare il binding dinamico di una particolare funzione membro va utilizzata la parola chiave 'virtual' nella dichiarazione della funzione membro. Il binding dinamico è una tecnica più costosa in termini di prestazioni e quindi di tempistica durante l’esecuzione in quanto vanno effettuati maggiori controlli prima dell'esecuzione della corretta funzione, rispetto al caso del binding statico. E' cosi consigliato utilizzarlo solo in caso di reale necessità e non per ogni funzione membro.

La parola chiave virtaul e quindi il binding dinamico non si puo' associare ai costruttori, ed è inefficente, nel constesto di una raccolta di puntatori di una classe base, applicarlo ad una funzione membro propria solo della classe derivata. Il binding dinamico consente infatti solo la scelta dinamica tra metodi che sono definiti nella classe base.

L'utilizzo della parola virtual è d'obbligo nella dichiarazione all'interno del corpo della classe base, mentre è facoltativa nel corpo della classe derivata, anche se viene consigliato farlo anche nella classe derivata per maggiore chiarezza. Nella definizione esterna del metodo non va invece piu' specificato l'attributo virtual.

Page 38: Vocabolario C++

Definizione di una funzione virtuale

class Nome_classe{

virtual Tipo_restituito Nome_funzione ( ...parametri... );...

};

class Employee{public:

virtual void print() const;...

};

Scopo: Definire una fuinzione collegata in binding dinamico che puo essere ridefinita nelle classi derivate. Quando la funzione viene chiamata il tipo del parametro implicto stabilisce quale versione della funzione viene eseguita.

staff[0]=new Employee("francesco",2000); staff[1]=new Employee("simone",3000); staff[2]=new Manager("nello",4000,"colleverde"); staff[0] -> print(); cout<<endl; staff[1] -> print(); cout<<endl; staff[2] -> print(); cout<<endl;

In questo modo verrà chiamato per gli oggetti puntati da staff[0] e staff[1] la print() della classe Employee di base e per l’oggetto puntato da staff[2] la fuzione di Manager

Page 39: Vocabolario C++

023. Vettori (vector)

Il tipo di dato vector è una classe che basandosi sul costrutto, di livello più basso, array, semplifica e potenzia l'uso di un tipo di dato aggregato, anche se con la limitazione di dover rinunciare a dei vettori multidimensionali (nel qual caso si puo' pensare di utilizzare vettori paralleli). Va inclusa la libreria vector se si vuole far uso dei vettori ( #include <vector> )

Sintassi:

vector<tipo_dato> nome_variabile;vector<tipo_dato> nome_variabile(dimensione_iniziale);

Esempi:

vector<double> salari(10);vector<complesso> compl;

La dichiarazione di una dimensione iniziale di un vettore è facoltativa.Per accedere a un elemento del vettore si utilizza la sintassi comune anche agli array:

espressione_vettore[espressione_intera]

Es: salari[0] //punta al primo elemento

Gli indici di un vettore di dimensione n, vanno da 0 a n-1, come analogamente per gli array.

vector<complesso> compl(5);compl[1] // punta al secondo elementocompl[0] // al primocompl[5] // espressione scorrettacompl[4] // punta all'ultimo elem.

Essendo una vera e propria classe, il costrutto vector è caratterizzato da alcune funzioni membro:

.size() restituisce la dimensione del vettore

.push_back(item) inserisce un elemento ‘item’ in fondo al vettore

.pop_back() elimina l'ultimo elemento del vettore

Gli oggetti vector possono essere restituiti dalle funzioni. Il passaggio di default ad una funzione è per lettura, mentre quello per riferimento va specificato esplicitamente con l'operatore &.

La classe vector, in quanto tale, ha un costruttore di default, che restituisce un vettore vuoto di elementi del tipo specifico

salari = vector<double>(); // sovrascrivo all'oggetto vettoriale quello che viene restituito dal costruttore di default della classe vector, che è in particolare un vettore vuoto.

Page 40: Vocabolario C++

024. Puntatori

Memoria statica e memoria dinamica

Tutti gli oggetti e le variabili discusse finora venivano memorizzate nella memoria cosidetta STACK. La memoria Stack è una memoria gestita in modo statico. Contiene le variabili e gli oggetti locali al blocco funzionale a cui ci si riferisce e ogni variabile o oggetto dichiarato viene allocato all'inizio dell'attivazione del blocco funzionale, e viene deallocato automaticamente alla fine dell'esecuzione del blocco. Per questo la memoria stack si dice anche automatica e le variabili che ci risiedono vengono dette automatiche. Esiste una memoria detta HEAP che è gestita invece in maniera dinamica, e cioè su richiesta del programmatore. Il programmatore può scegliere di allocare e deallocare oggetti e variabili nella memoria heap durante il programma.

Per allocare un oggetto o una var. nell'heap:

new nome_tipo;new nome_tipo(espressione);

Es. new complesso(1,3);new int;

Il comando new alloca nell'heap una cella di memoria per una variabile, o un oggetto e restituisce un puntatore a quella variabile, o a quell'oggetto. Si chiarirà poi come utilizzare il comando e cosa è un puntatore.

Se le variabili automatiche avevano un ‘nome’ con le quali venivano memorizzate, le variabili allocate nell’heap sono ‘mute’. Non hanno cioè un nome proprio e possono essere raggiunte solamente con un puntatore.

//============================================================//

Sintassi

I puntatori sono tipi di dato che permettono di memorizzare l'indirizzo di memoria di un oggetto, o di una variabile. Ogni oggetto o variabile ha un indirizzo che può essere contenuto in una variabile puntatore. Per ogni tipo di variabile e per ogni tipo di variabile o oggetto esiste un particolare puntatore.

Sintassi:nome_tipo* nome_variabile;nome_tipo* nome_variabile = espressione;

Esempio:complesso* z1; //puntatore ad un oggetto complessoint* i; //puntatore ad un intero

Page 41: Vocabolario C++

complesso* e int* sono tipi di dato, in particolarte sono un puntatore ad un oggetto complesso e un puntatore ad una variabile intera. z1 e i sono variabili e servono a contenere l'indirizzo di memoria di un oggetto o variabile.

Ad un puntatore si può assegnare sia l'indirizzo di memoria di un oggetto o variabile dello stack che dell'heap. Si puo' anche associare un valore nullo. Questo si effettua con la parola chiave NULL e non semplicemente senza specificare nessuna espressione. In quel caso infatti il contenuto momentaneo della variabile puntatore viene convertito in esadecimale (il modo in cui sono scritti gli indirizzi) e il puntatore avrà sì un contenuto, ma punterà ad una cella di memoria ‘a caso’.

L'espressione che segue la dichiarazione di un puntatore puo' cosi essere completata:

int n;int* p = &n; //Ora p punta a n. Dentro a p c'è l'indirizzo di memoria di n. n si trova nello

stack così come p.

o ancora

complesso* z1 = new complesso; //viene chiamato il costruttore di defaultcomplesso* z2 = new complesso(3,6); //costruttore con parametri

Il comando new infatti restituisce un puntatore ad un complesso che viene allocato nella memoria heap. L'unico modo per accedere a quell'oggetto sarà attraverso il puntatore.

complesso* z3 = NULL; //puntatore che per ora nn punta a nullaz3 = new complesso(8);

//============================================================//

Deriferimento e accesso

Per accedere al contenuto dell'oggetto o della variabile puntata da un puntatore si utilizza l'operatore di de-riferimento '*'.

int n;int* p = &n;*p = 12; //assegno 12 al contenuto della variabile puntata da p

//è come scrivere n=12;

L'operatore di deriferimento ha precedenza rispetto all'operatore punto, quindi per utilizzare una funziome membro di un oggetto attraverso un puntatore va utilizzata questa sintassi:

(*nome_puntatore).funzione_mebro(parametri);

Page 42: Vocabolario C++

es: complesso* z2 = new complesso(3,6);double y = (*z2).reale();

oppure indifferentemente esiste l'operatore freccia che semplifica quest'operazione:

nome_puntatore -> funzione_membro(parametri);

es: complesso* z2 = new complesso(3,6);double y = z2 -> reale();

E' possibile deallocare e quindi liberare la memoria nell'heap ad un certo punto del programma. E' buona norma farlo sempre alla chiusura del programma, altrimenti quell’area di memoria rimarrà occupata (fino allo spegnimento del computer) e gli altri programmi non potranno piu accerderci. Quest'operazione si puo' effettuare se si è utilizzato il comando new e quindi il puntatore in questione punta ad un oggetto o ad una variabile nell'heap.

Sintassi:

delete nome_puntatore;

int* p = new int(9); //p punta ad una variabile intera collocata nell'heap inizializzata a 9*p = *p + 1; //il contenuto dell'intero puntato da p viene incrementatocout << *p; //stampa 10delete p; //viene deallocata la memoria nell'heap che conteneva l'intero che

valeva 10p = NULL;

complesso* c2 = new complesso(2,4);cout << c2 -> reale();delete c2;c2 = NULL;

Esiste la possibilità all'interno di una funzione membro di utilizzare il puntatore 'this' che è associato al parametro implicito.

double complesso::re (){

return this -> real;}

//============================================================//

Array e puntatori

Page 43: Vocabolario C++

Quando viene dichiarato un array il nome dell’array è un puntatore al primo elemento della variabile array.

int a[10];int* p = a;*a = 10 oppure a[0] = 10;*(p+3) oppure *(a+3) oppure a[3];

I puntatori contengono un indirizzo di memoria espresso in valore esadecimale. Gli operatori +,-,++,-- sono in grado di manipolare correttamente gli operatori per eseguire somme ecc...Da un elemento all’altro dell’array le celle di memoria di distanza possono essere anche piu di una ma il compilatore pensa da solo ad aggiornare nel modo corretto il puntatore dopo un’operazione algebrica in modo che punti alla cella di memoria dell’elemento desiderato.

Il nome di un array nel blocco in cui viene dichiarato non puo’ essere aggiornato con il contenuto di qualsiasi altro puntatore. Quando viene pero’ passato un array ad una funzione, questo passaggio viene fatto per riferimento e viene passato al blocco della funzione un puntatore che contiene l’indirizzo di memoria del primo elemento dell’array. Questo puntatore puo’ essere modificato invece all’interno del blocco della funzione.

void funzione(int p[]) {int* q;const int* r;int s[10];....

p=q ; //correttop=r; //NON CORRETTOp=s; //corretto

q=p; //correttoq=r; //NON CORRETTOq=s; //corretto

r=q; //correttor=s; //correttor=p; //corretto

s=q; //NON CORRETTOs=r; //NON CORRETTOs=p; //NON CORRETTO

I puntatori possono essere dichiarati const. Sintassi: const tipo_dato* nome_puntatore. I puntatori const possono essere sovrascritti con il constenuto di un altro puntatore const, con quello di un puntatore normale, e con quello di un identificatroe di array. Al contrario un puntatore normale non puo’ essere aggiornato con il valore di un puntatore const ma solo con quello di un puntatore normale, o con quello di un array.

Page 44: Vocabolario C++

Se si alloca dinamicamente un array di oggetti o di variabili:

const int n =10;complesso* serie = new complesso[n];

serie[i] <= punta all’i-esimo complesso

delete[] serie; <= dealloca tutto l’array, e non solo il primo elelemento (delete senza [])