Fondamenti di Programmazione - marco sechiDocente: A. Saetti Fondamenti di Programmazione...

Post on 06-Mar-2021

8 views 0 download

Transcript of Fondamenti di Programmazione - marco sechiDocente: A. Saetti Fondamenti di Programmazione...

1A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Fondamenti di ProgrammazioneIngegneria dell’Automazione Industriale

Ingegneria Elettronica e delle Comunicazioni

Alessandro Saetti& Marco Sechi

(email: {saetti,marco.sechi}@ing.unibs.it)

Università degli Studi di BresciaA.A. 2012/2013

2A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizi sulle classi (1º parte)1. Definire la classe delle date del calendario con

– Un costruttore che inizializzi la data al capodanno del 2000;– Un metodo che inizializzi la data con tre interi acquisiti da tastiera;– Un metodo che visualizzi la data;– Un metodo che faccia avanzare la data di una giornata.

Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi la data con tre interi acquisiti da tastiera, faccia avanzare la data di 15 giorni ed infine visualizzi la data risultante.

3A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizi sulle classi (1º parte)2. Definire la classe dei numeri complessi con

• Un costruttore che inizializzi il numero complesso rappresentato con dati acquisiti da tastiera;

• Un costruttore che inizializzi il numero complesso con una data parte reale ed una data parte immaginaria;

• Un metodo che produca un numero complesso ottenuto incrementando un dato numero complesso con il numero complesso della classe;

• Un metodo che visualizzi il numero complesso nella forma “x + yi” (“x - yi” se y è negativo).

Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi un numero complesso con dati acquisiti da tastiera, incrementi il numero complesso acquisito con il numero complesso 3.5 – 4i, ed infine visualizzi il numero complesso risultante.

4A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Definire la classe delle date del calendario con– Un costruttore che inizializzi la data al capodanno del 2000;– Un metodo che inizializzi la data con tre interi acquisiti da tastiera;– Un metodo che visualizzi la data;– Un metodo che faccia avanzare la data di una giornata.

Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi la data con tre interi acquisiti da tastiera, faccia avanzare la data di 15 giorni ed infine visualizzi la data risultante.

5A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sulle classi (1°parte)

/*************************************************************************** Nome: casa1-data.c ** Autore: Alessandro Saetti ** Data: 6/4/10 ***************************************************************************/

#include <iostream>#include <stdlib.h>

/* Nome: main* Scopo: Gestione delle date* Input: -* Output: 0 se il programma termina correttamente*/

int main() {

system("pause");return 0;

}

Impostiamo la solita struttura iniziale  di un programma C, aggiungendo eventuali commenti

// Definizione classe

Definire la classe delle date del calendario con–Un costruttore che inizializzi la data al capodanno del 2000;–Un metodo che inizializzi la data con tre interi acquisiti da tastiera;–Un metodo che visualizzi la data;–Un metodo che faccia avanzare la data di una giornata.

Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi la data con tre interi acquisiti da tastiera, faccia avanzare la data di 15 giorni ed infine visualizzi la data risultante.

// Utilizzo della classe

Per la gestione dell’I/O utilizzeremo gli oggetti globali di I/O cin e cout abbinati agli operatori di flusso << e >> per cui Includiamo <iostream>

6A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sulle classi (1°parte)

Iniziamo ad impostare la definizione per la classe Data.

Definire la classe delle date del calendario con–Un costruttore che inizializzi la data al capodanno del 2000;–Un metodo che inizializzi la data con tre interi acquisiti da tastiera;–Un metodo che visualizzi la data;–Un metodo che faccia avanzare la data di una giornata.

Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi la data con tre interi acquisiti da tastiera, faccia avanzare la data di 15 giorni ed infine visualizzi la data risultante.

class Data{

public:Data()

private:int aa, mm, gg;

};

/* Nome: Data::Data* Scopo: Costruttore di default della classe Data* Input: -* Output: -*/

Data::Data() {

gg = mm = 1;aa = 2000;

}

Implementiamo il costruttore di default (esternamente alla classe)

// l’operatore binario di risoluzione di visibilità// :: “qualifica” l’appartenenza alla classe

// Costruttore di default

// Dati membro o attributi

Ricordiamoci che per il costruttore nonsi deve dichiarare alcun valore di ritorno

7A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sulle classi (1°parte)Definire la classe delle date del calendario con

–Un costruttore che inizializzi la data al capodanno del 2000;–Un metodo che inizializzi la data con tre interi acquisiti da tastiera;–Un metodo che visualizzi la data;–Un metodo che faccia avanzare la data di una giornata.

Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi la data con tre interi acquisiti da tastiera, faccia avanzare la data di 15 giorni ed infine visualizzi la data risultante.

void Data::acquisisci() {

cout << "Inserisci giorno: ";cin >> gg;cout << "Inserisci mese: ";cin >> mm;cout << "Inserisci anno: ";cin >> aa;

}

class Data{

public:Data()void acquisisci();

private:int aa, mm, gg;

};

Ricordiamoci di inserire il tiporestituito dalla funzione‐membro della classe (anche se void)

#include <iostream>…using namespace std;

Implementiamo, all’esterno della definizione della classe, la funzione membro acquisisci()

Inseriamo l'istruzione "using namespace std" ("using‐directive"). Con essa si rendono accessibili tutti i membri del namespace std senza doverli qualificare ad ogni chiamata mediante l'operatore di risoluzione dello scope ::. Pertanto gli oggetti globali di I/O std::cin e std::cout potranno essere richiamati semplicemente con cin e cout.

Aggiungiamo alla definizione della classe la dichiarazione della funzione‐membro acquisisci()

Per la gestione dell’I/O utilizziamo gli oggetti globali di I/O cin e cout abbinati agli operatori di flusso << e >>.

Per la gestione dell’I/O utilizziamo gli oggetti globali di I/O cin e cout abbinati agli operatori di flusso << e >>.

8A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sulle classi (1°parte)

Aggiungiamo alla definizione della classe la dichiarazione della funzione‐membro stampa() ricordandoci di aggiungere il tipo restituito

Definire la classe delle date del calendario con–Un costruttore che inizializzi la data al capodanno del 2000;–Un metodo che inizializzi la data con tre interi acquisiti da tastiera;–Un metodo che visualizzi la data;–Un metodo che faccia avanzare la data di una giornata.

Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi la data con tre interi acquisiti da tastiera, faccia avanzare la data di 15 giorni ed infine visualizzi la data risultante.

/* Nome: Data::stampa* Scopo: Stampa la data* Input: -* Output: -*/

void Data::stampa(){

cout << gg << "/" << mm << "/" << aa << endl;}

class Data{

public:Data()void acquisisci();void stampa();

private:int aa, mm, gg;

};

Implementiamo, esternamente alla classe, la funzione membro stampa() che mostra a video la data 

9A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sulle classi (1°parte)

Data::Data(){

aa=2000;gg=mm=1;

}

void Data::Acquisisci() {

cout << "Inserisci giorno: ";cin >> gg;cout << "Inserisci mese: ";cin >> mm;cout << "Inserisci anno: ";cin >> aa;

}

void Data::Stampa(){

cout << gg << "/" << mm << "/“ << aa << endl;}

Inventiamoci quindi un main() che ci consenta di testare tutte le funzionalità fino a questo punto implementate

int main(){

Data d;d.stampa();d.acquisisci();d.stampa();

}

#include <iostream>using namespace std;

class Data{

public:Data(); void acquisisci();void avanza();void stampa();

private:int aa, mm, gg;

};

Prima di proseguire possiamo testare il programma che abbiamo implementato fino a questo punto.

10A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sulle classi (1°parte)Definire la classe delle date del calendario con

–Un costruttore che inizializzi la data al capodanno del 2000;–Un metodo che inizializzi la data con tre interi acquisiti da tastiera;–Un metodo che visualizzi la data;–Un metodo che faccia avanzare la data di una giornata.

Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi la data con tre interi acquisiti da tastiera, faccia avanzare la data di 15 giorni ed infine visualizzi la data risultante.

void Data::Avanza(){

gg++; // incremento il giorno

// 1) Calcolo l’ultimo giorno// del mese indicato in mm

// 2) se gg è maggiore dell’ultimo// giorno del mese pongo gg = 1 // ed incremento mm di uno

// 3) se mm>12 incremento l’anno// e pongo mm=1

}

( ((aa % 400)==0) || ( ((aa % 4)==0) && ((aa % 100)!=0) ) )

Per determinare l’ultimo giorno di ogni mese devo disporre di un elenco contenente tale valore distinto per mese. Il seguente array potrebbe essere adatto ai nostri scopi:int v[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

Occorre però tener conto che febbraio, negli anni bisestili, ha 29 giorni. Un anno è bisestoquando è multiplo di 400 oppure se è divisibile per 4 ma non per 100. La condizione sottostante consente quindi di valutare se un anno aa è bisestile o meno:

. . . e poi procedo, se necessario,  con opportune correzioni (Normalizzazione).

// CORREGGO SE GG NON E’ SENSATO

Per passare al giorno successivoincremento la variabile gg di 1 …

11A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sulle classi (1°parte)

#define TRUE 1#define FALSE 0. . ./* Nome: Data::bisestile* Scopo: Determina se l'anno della data e' bisestile* Input: -* Output: TRUE, se l'anno e' bisestile* FALSE, altrimenti*/

int Data::bisestile() {if (aa % 4 == 0 && aa % 100 != 0 || aa % 400 == 0)

return TRUE;return FALSE;

}

Per determinare se è un anno bisestile definiamo la funzione‐membro privata sottostante:

/* Nome: Data::giorni* Scopo: Restituisce il numero di giorni in un mese* Input: int mese: il mese da esaminare* Output: il numero di giorni di mese*/

int Data::giorni(int mese) {int v[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};if (mese == 2 && bisestile())

return 29; else

return v[mese-1];}

Mentre per  determinare l’ultimo giorno del mese definiamo questa funzione‐membro privata:

Se mese==2 ed aa è bisestile allora i giornisono 29 altrimenti sono v[mese‐1]

void Data::Avanza(){

gg++;

// 1) Calcolo l’ultimo giorno // del mese indicato in mm

// 2) . . .

// 3) . . . }

Inseriamo le due #define TRUE e FALSE per rendere più leggibile il codice della funzione‐membro bisestile()

12A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sulle classi (1°parte)

class Data{

public:Data();void acquisisci();void avanza();void stampa();

private:int aa, mm, gg;int bisestile();int giorni ();

};

le due funzioni membro bisestile() e giorni()sono destinate ad uso interno per la classe per cui le aggiungiamo alla sezione private:. La funzione‐membro avanza() , che deve essere usata nel main(), verrà posta nella sezione public:

void Data::Avanza(){

gg++; // incremento il giorno// 1) Calcolo il nr di giorni // del mese indicato in mm

// 2) se gg è maggiore dell’ultimo// giorno del mese pongo gg = 1 // ed incremento mm di uno

// 3) se mm>12 incremento l’anno// e pongo mm=1

}

Continuiamo con l’implementazione della funzione‐membro avanza()

if (gg > giorni(mm)) {gg = 1;mm++;

}

if (mm > 12) {mm = 1;aa++;

}

Aggiorniamo la definizione della classe Data:

13A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sulle classi (1°parte)

Possiamo inserire le istruzioni utilizzate per  la “normalizzazione” della variabile gg all’interno di una funzione‐membro privata che chiameremo normalizza():

Mentre l’implementazione della funzione‐membro avanza() che utilizza la nuova funzione‐membro normalizza() diventa:

/* Nome: Data::normalizza* Scopo: Normalizza la data* Input: -* Output: -* Note: Suppone che i giorni della data eccedano al* piu' di una unita' il numero di giorni possibili*/

void Data::normalizza() {if (gg > giorni(mm)) {

gg = 1;mm++;

} if (mm > 12) {

mm = 1;aa++;

}}

/* Nome: Data::avanza* Scopo: Incrementa la data * corrente di un giorno* Input: -* Output: -*/

void Data::avanza() {

gg++;normalizza();

}

class Data{

public:Data();void acquisisci();void avanza();void stampa();

private:int aa, mm, gg;bool bisestile();int giorni ();void normalizza();

};

Completiamo la definizione della classe Datainserendo nella sezione private: la dichiarazione 

della funzione‐membro normalizza():

14A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sulle classi (1°parte)

Definire la classe delle date del calendario con–Un costruttore che inizializzi la data al capodanno del 2000;–Un metodo che inizializzi la data con tre interi acquisiti da tastiera;–Un metodo che visualizzi la data;–Un metodo che faccia avanzare la data di una giornata.

Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi la data con tre interi acquisiti da tastiera, faccia avanzare la data di 15 giorni ed infine visualizzi la data risultante.

int main() {

Data oggi;int i;

oggi.acquisisci();for (i = 0; i < 15; i++)

oggi.avanza();cout << "Data dopo 15 giorni: ";oggi.stampa();

system("pause");return 0;

}

Sfruttando la classe Data e le sue funzioni‐membro possiamo ora implementare il nostro main()

Acquisisco una data

Avanzo di 15 giorni tramite un ciclo for

Stampo la data

15A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sull’uso delle classi (1°parte)Soluzione completa …

/*************************************************************************** Nome: casa1-data.c ** Autore: Alessandro Saetti ** Data: 6/4/10 ***************************************************************************/

#include <iostream>#include <stdlib.h>#define TRUE 1#define FALSE 0using namespace std;class Data {

public:Data();void acquisisci();void stampa();void avanza();

private:int gg, mm, aa;int bisestile();int giorni(int mese);void normalizza();

};

16A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sull’uso delle classi (1°parte)

.. soluzione completa …/* Nome: Data::Data* Scopo: Costruttore di default della classe Data* Input: -* Output: -*/

Data::Data() {gg = mm = 1;aa = 2000;

}/* Nome: Data::acqusisci* Scopo: Inizializzazione della data con interi acquisiti da tastiera* Input: -* Output: -*/

void Data::acquisisci() {cout << "Inserisci giorno: ";cin >> gg;cout << "Inserisci mese: ";cin >> mm;cout << "Inserisci anno: ";cin >> aa;

}

17A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sull’uso delle classi (1°parte).. soluzione completa …

/* Nome: Data::stampa* Scopo: Stampa la data* Input: -* Output: -*/

void Data::stampa() {cout << gg << "/" << mm << "/" << aa << endl;

}/* Nome: Data::avanza* Scopo: Incrementa la data corrente di un giorno* Input: -* Output: -*/

void Data::avanza() {gg++;normalizza();

}/* Nome: Data::bisestile* Scopo: Determina se l'anno della data e' bisestile* Input: -* Output: TRUE, se l'anno e' bisestile* FALSE, altrimenti*/

18A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sull’uso delle classi (1°parte).. soluzione completa …

int Data::bisestile() {if (aa % 4 == 0 && aa % 100 != 0 || aa % 400 == 0)

return TRUE;return FALSE;

}/* Nome: Data::giorni* Scopo: Restituisce il numero di giorni in un mese* Input: int mese: il mese da esaminare* Output: il numero di giorni di mese*/

int Data::giorni(int mese) {int v[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};if (mese == 2 && bisestile())

return 29; else

return v[mese-1];}/* Nome: Data::normalizza* Scopo: Normalizza la data* Input: -* Output: -* Note: Suppone che i giorni della data eccedano al piu' di * una unita' il numero di giorni possibili */

19A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 1Esercizi sull’uso delle classi (1°parte).. soluzione completa.

void Data::normalizza() {if (gg > giorni(mm)) {

gg = 1;mm++;

} if (mm > 12) {

mm = 1;aa++;

}}/* Nome: main* Scopo: Gestione delle date* Input: -* Output: 0 se il programma * termina correttamente*/

int main() {

Data oggi;int i;oggi.acquisisci();for (i = 0; i < 15; i++)

oggi.avanza();cout << "Data dopo 15 giorni: ";oggi.stampa();system("pause");return 0;

}

20A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2Definire la classe dei numeri complessi con• Un costruttore che inizializzi il numero complesso rappresentato con dati

acquisiti da tastiera;• Un costruttore che inizializzi il numero complesso con una data parte reale ed

una data parte immaginaria;• Un metodo che produca un numero complesso ottenuto incrementando un dato

numero complesso con il numero complesso della classe;• Un metodo che visualizzi il numero complesso nella forma “x + yi” (“x - yi”

se y è negativo).Scrivere un programma C++ che, sfruttando la classe precedentemente

definita, inizializzi un numero complesso con dati acquisiti da tastiera, incrementi il numero complesso acquisito con il numero complesso 3.5 – 4i, ed infine visualizzi il numero complesso risultante.

21A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2Esercizi sulle classi (1°parte)

/*************************************************************************** Nome: lab1-complesso.c ** Autore: Alessandro Saetti ** Data: 6/4/10 ***************************************************************************/

#include <iostream>#include <stdlib.h>

/* Nome: main* Scopo: Gestione dei numeri complessi* Input: -* Output: 0 se il programma termina correttamente*/

int main() {

system("pause");return 0;

}

Impostiamo la solita struttura iniziale  di un programma C, aggiungendo eventuali commenti

// Definizione classe

Definire la classe dei numeri complessi con•Un costruttore che inizializzi il numero complesso rappresentato con dati acquisiti da tastiera;•Un costruttore che inizializzi il numero complesso con una data parte reale ed una data parte immaginaria;•Un metodo che produca un numeri complesso ottenuto incrementando un dato numero complesso con il numero complesso della classe;

•Un metodo che visualizzi il numero complesso nella forma  “x + yi” (“x ‐ yi” se y è negativo).Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi un numero complesso con dati acquisiti da tastiera, incrementi il numero complesso acquisito con il numero complesso 3.5 – 4i, ed infine visualizzi il numero complesso risultante.

// Utilizzo della classe

22A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2Esercizi sulle classi (1°parte)

/* Nome: Complesso* Scopo: Inizializza il numero

complesso con numeri acquisiti da tastiera

* Input: -* Output: -*/

Complesso::Complesso() {

cout << "Parte reale: ";cin >> reale;cout << "Parte immaginaria: "; cin >> immag;

}

Implementiamo il costruttore di default (quello senza argomenti)

Definire la classe dei numeri complessi con•Un costruttore che inizializzi il numero complesso rappresentato con dati acquisiti da tastiera;•Un costruttore che inizializzi il numero complesso con una data parte reale ed una data parte immaginaria;•Un metodo che produca un numeri complesso ottenuto incrementando un dato numero complesso con il numero complesso della classe;

•Un metodo che visualizzi il numero complesso nella forma  “x + yi” (“x ‐ yi” se y è negativo).Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi un numero complesso con dati acquisiti da tastiera, incrementi il numero complesso acquisito con il numero complesso 3.5 – 4i, ed infine visualizzi il numero complesso risultante.

/* Nome: Complesso::Complesso* Scopo: Costruttore alternativo della * classe complesso* Input: float r: la parte reale del* numero complesso* float i: la parte immaginaria* del numero complesso* Output: -*/

Complesso::Complesso(float r, float i) {

reale = r;immag = i;

}

... e il secondo costruttore, in overloading, distinto per la differente  lista di argomenti

23A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2Esercizi sulle classi (1°parte)

/* Nome: Complesso::somma* Scopo: Somma un numero complesso al numero complesso rappresentato * dall'oggetto* Input: Complesso addendo: il numero complesso da sommare* Output: Restituisce la somma tra i due* numeri complessi*/

Complesso Complesso::somma(Complesso addendo) {return Complesso (reale + addendo.reale, immag + addendo.immag);

}

Implementiamo la funzione membro somma() che aggiunge al numero complesso della classe il complesso passato come addendo …

Definire la classe dei numeri complessi con•Un costruttore che inizializzi il numero complesso rappresentato con dati acquisiti da tastiera;•Un costruttore che inizializzi il numero complesso con una data parte reale ed una data parte immaginaria;•Un metodo che produca un numeri complesso ottenuto incrementando un dato numero complesso con il numero complesso della classe;

•Un metodo che visualizzi il numero complesso nella forma  “x + yi” (“x ‐ yi” se y è negativo).Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi un numero complesso con dati acquisiti da tastiera, incrementi il numero complesso acquisito con il numero complesso 3.5 – 4i, ed infine visualizzi il numero complesso risultante.

void Complesso::stampa() {if ( (reale!=0) || (immag==0) )

cout << reale;if (immag!=0) {

if ((immag > 0) && (reale!=0)) cout << "+";if (immag!=1) cout << immag;

cout << "i";}

}

… e successivamente quella che stampa a video il numero complesso

24A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2Esercizi sulle classi (1°parte)

class Complesso {public:

Complesso();Complesso(float r, float i);Complesso somma(Complesso addendo);void stampa();

private:float reale, immag;

};

Definiamo quindi la classe Complesso.

Definire la classe dei numeri complessi con•Un costruttore che inizializzi il numero complesso rappresentato con dati acquisiti da tastiera;•Un costruttore che inizializzi il numero complesso con una data parte reale ed una data parte immaginaria;•Un metodo che produca un numeri complesso ottenuto incrementando un dato numero complesso con il numero complesso della classe;

•Un metodo che visualizzi il numero complesso nella forma  “x + yi” (“x ‐ yi” se y è negativo).Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi un numero complesso con dati acquisiti da tastiera, incrementi il numero complesso acquisito con il numero complesso 3.5 – 4i, ed infine visualizzi il numero complesso risultante.

Ricordiamoci di inserire, per ogni singola funzione‐membro, il tipo di dato restituito

Sfruttando la classe Complesso e le sue funzioni‐membro possiamo implementare ora il main():

int main() {Complesso n1, n2(3.5, 4);n1.stampa();n1 = n1.somma(n2);cout << " + ";n2.stampa();cout << " = ";n1.stampa();cout << endl;system("pause");return 0;

}

Definiamo due istanze della classe Complesso: n1 e n2.

Stampo n1 e poi lo incremento di n2

Stampo n2 e il nuovo valore di n1

25A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2Esercizi sull’uso delle classi (1°parte)Soluzione completa …

/*************************************************************************** Nome: lab1-complesso.c ** Autore: Alessandro Saetti ** Data: 6/4/10 ***************************************************************************/

#include <iostream>#include <stdlib.h>using namespace std;class Complesso {public:

Complesso(float r, float i);Complesso();Complesso somma(Complesso addendo);void stampa();

private:float reale, immag;

};/* Nome: Complesso* Scopo: Inizializza il numero complesso con numeri acquisiti da tastiera* Input: -* Output: -*/

26A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2Esercizi sull’uso delle classi (1°parte)… soluzione completa …

Complesso::Complesso() {cout << "Parte reale: ";cin >> reale;cout << "Parte immaginaria: "; cin >> immag;

}/* Nome: Complesso::Complesso* Scopo: Costruttore alternativo della classe complesso* Input: float r: la parte reale del numero complesso* float i: la parte immaginaria del numero complesso* Output: -*/

Complesso::Complesso(float r, float i) {reale = r;immag = i;

} /* Nome: Complesso::somma* Scopo: Somma un numero complesso al numero complesso rappresentato * dall'oggetto* Input: Complesso addendo: il numero complesso da sommare* Output: Restituisce la somma tra i due numeri complessi*/

27A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2Esercizi sull’uso delle classi (1°parte)… soluzione completa …

Complesso Complesso::somma(Complesso addendo) {return Complesso (reale + addendo.reale, immag + addendo.immag);

}/* Nome: Complesso::stampa* Scopo: Stampa il numero complesso * Input: -* Output: -*/

void Complesso::stampa() {if ( (reale!=0) || (immag==0) )

cout << reale;if (immag!=0) {

if ((immag > 0) && (reale!=0)) cout << "+";if (immag!=1) cout << immag;

cout << "i";}

}/* Nome: main* Scopo: Gestione dei numeri complessi* Input: -* Output: 0 se il programma termina correttamente*/

28A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2Esercizi sull’uso delle classi (1°parte)… soluzione completa.

int main() {

Complesso n1, n2(3.5, 4);n1.stampa();n1 = n1.somma(n2);cout << " + ";n2.stampa();cout << " = ";n1.stampa();cout << endl;system("pause");return 0;

}

29A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2 – Soluzione alternativaEsercizi sulle classi (1°parte)

Vediamo come possiamo implementare la soluzione dell’esercizio 2 sfruttando l’overload degli operatori.

OVERLOAD DEGLI OPERATORI

Prima di procedere ricordiamo che una famiglia di funzioni aventi lo stesso nome, ma un diverso set di argomenti (signature), è detta in rapporto di overloading, o sovraccaricata. 

L’ overloading , oltre alle funzioni, può essere applicato ai costruttori e agli operatori. 

Illustriamo ora brevemente la tecnica di overload degli operatori.

Esercizio 2 – Soluzione alternativa

30A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Overload degli operatoriEsercizi sulle classi (1°parte)

Overload degli operatori…In C++ sono definiti dei tipi nativi (esempio: int, char, float, double ...) sui quali è possibile applicare  un insieme di operazioni convenzionali (rappresentate da simboli come +, * , / , etc…)

Non sempre la realtà  può essere rappresentata mediante i tipi nativi (si pensi a: numeri complessi, matrici, aggregazioni di dati, etc...) ma occorre fare ricorso a tipi astratti come ad esempio le classi.La semantica delle operazioni applicabili a tali tipi astratti potrebbe differire da quella comunemente associata ai simboli convenzionali per cui nasce la necessità di ridefinirne il significato.

Operazione di somma intesa come unione

Ad esempio il simbolo + può assumere significati diversi a seconda del tipo di dato trattato. Prendiamo ad esempio queste operazioni di “addizione”:

Operazione di somma applicata alle matrici

Il C++ permette di ridefinire il significato di un simbolo convenzionale rendendolo adatto al tipo astratto definito dal programmatore. La tecnica che consente questo è l’overload degli operatori

L’uso del simbolo convenzionale per richiamare le operazioni definite in una classe permette una notazione più compatta che evita chiamate a funzioni specifiche che rendono meno leggibile il codice.

31A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Overload degli operatoriEsercizi sulle classi (1°parte)

Overload degli operatori…

Operazione espressa consimboli convenzionali

Operazione implementata mediantechiamate a funzioni specifiche.

Y=A+B*C

Y=SOMMA(A,MOLTIPLICA(B,C))

Nell’esempio sottostante l’immediatezza della formula, quando utilizzo gli operatori + e * rispetto a quella che usa le funzioni somma() e moltiplica(), è evidente :

Per ottenere l'overload di un operatore bisogna creare una funzione il cui nome deve essere costituito dalla parola‐chiave operator seguita, con o senza blank, dal simbolo dell'operatore sovraccaricato (ad esempio: operator+). Gli argomenti della funzione corrispondono agli operandi dell’operatore.

tipo-restituito operatorOPERATORE (lista-argomenti)

La ridefinizione di un operatore deve essere la più vicina possibile al senso che l’operatore ha per i tipi nativi.  Anche se è possibile definire in modo arbitrario ciò che fa un operatore si crea solo confusione quando questo determina una semantica inaspettata (si immagini una ridefinizione dell’operatore + che effettua un’operazione simile ad una sottrazione)

32A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Overload degli operatoriEsercizi sulle classi (1°parte)

E' possibile effettuare l'overloading degli operatori mediante funzioni‐membro della classe stessa. In questo caso l’oggetto chiamante coincide con il primo operando. Segue che le funzioni‐membro associate ad un operatore binario abbiano un solo parametro (corrispondente al right‐operand) mentre quelle relative ad operatori unari nessuno.

Vettore*Scalare Scalare*Vettore

Supponiamo di aver definito la classe Vettore2D e di voler implementare l’overload dell’operatore “*” in modo che abbiano significato le due operazioni:

… overload degli operatori …

L’overloading mediante funzioni‐membro non è sempre attuabile. Infatti questa modalità implica che l’operando a sinistra debba essere un membro della classe ma questo non  sempre possibile (si pensi alla somma tra un numero reale e uno immaginario oppure agli operatori di flusso >> e <<). Ecco un esempio:

Il prodotto di uno scalare per un vettore

class MyClass {...

MyClass operator+(MyClass);MyClass operator++(); // prefissaMyClass operator--(int notused); // suffissa

...};

main() {...

C=A+B // oppure C=A.operator+(B);++C // oppure C.operator++();C-- // oppure C.operator++(1);

...}

++, ‐‐ : operatori unari

+ : operatore binario

In entrambi i casi l’overload dell’operatore deve restituire un oggetto della classe Vettore2D. Nel primo caso il left‐operand Vettore appartiene alla classe Vettore2D e quindi la funzione‐operatore può essere funzione membro della classe stessa. Nel secondo caso il primo operando non appartiene alla classe Vettore2D e pertanto la funzione‐operatore deve essere esterna alla classe Vettore2D :

C=A+B; è equivalente aC=A.operator+(B);

Con l’overloading dell’operatore la chiamata della  funzione "scompare" dal codice del programma e al suo posto viene usata una più "semplice e concisa rappresentazione“ costituita dal simbolo convenzionale associato all’operazione.

33A.A. 2012/2013

Vettore2D operator*(float a, Vettore2D B) {

return Vettore2D (a*B.x, a*B.y); }

Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Overload degli operatoriEsercizi sulle classi (1°parte)

… overload degli operatori

int main() {

Vettore2D P;Vettore2D A(4.2,4);P = A * 3; // oppure A.operator*(3);... // Istruzioni di di outputP = 3 * A;... // Istruzioni di di output

}

Ecco un main() di esempio che utilizza la classe Vettore2D

class Vettore2D {public:

Vettore2D();Vettore2D(float r, float i);Vettore2D operator*(float);friend Vettore2D operator*(float,Vettore2D);...

private:float x, y;

};

Vettore2D Vettore2D::operator*(float b) {

return Vettore2D (x*b, y*b ); }

Overloading mediante una funzione esterna alla classe

Una funzione friend in una classe ha accesso ai  membri privati della classe pur non essendone  membro

Overloading mediante una funzione membro

Vettore2D::Vettore2D(float a, float b) {

x = a;y = b;

}

Vettore2D::Vettore2D() {

x = 0;y = 0;

}

CostruttoriImplementazione della classe di esempio Vettore2D:

Esempio di esecuzione

senza friend i membri privati x e ydi B non risulterebbero accessibili!

34A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Overload degli operatoriEsercizi sulle classi (1°parte)

• Gli operatori per i quali è ammesso l’overload sono: Alcune precisazioni utili relative all’overload degli operatori

• Gli operatori per i quali non è ammesso l’overload sono: . :: .* ?: sizeof typeid• Non si può ridefinire un operatore che opera su i tipi nativi (int, char, float,…) poiché questi non sono ne classi ne strutture. Quindi la ridefinzione int operator+(int, int); non è permessa

• Non si può cambiare l’arità (numero di operandi) di un operatore e neppure la sua associatività• Non è concesso "inventare" nuovi simboli, ma si devono utilizzare solo quelli degli operatori esistenti.  • Le regole di precedenza restano legate al simbolo e non dipendono dal nuovo significato che l’operatore ha assunto con l’overloading (ad esempio l’operatore * avrà sempre precedenza sul +).

• E’ possibile ridefinire più volte lo stesso operatore e l'ambiguità, come nel caso delle funzioni, viene risolta in base al contesto degli operandi, riconoscendone il tipo e decidendo di conseguenza quale definizione operatore applicare. 

• Un operatore unario può essere ridefinito come funzione membro senza argomenti oppure come funzione non membro con un argomento. Analogamente un operatore binario può essere ridefinito come funzione membro con un argomento oppure come funzione non membro con due argomenti

• gli argomenti‐operandi sono generalmente passati by reference e dichiarati const, per maggiore sicurezza (const) e rapidità di esecuzione (passaggio by reference);

• L’overload deve essere esplicito: fare l’overload di = non condiziona +=, ‐= o !=

35A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Overload degli operatori di flussoEsercizi sulle classi (1°parte)

Overload degli operatori di flusso << e >> …Prima di procedere con l’overload degli operatori di flusso analizziamo la gestione dell’I/O implementata nella libreria iostream del C++.

La libreria iostream del C++ mette a disposizione un insieme di classi, funzioni ed oggetti globali per l'esecuzione delle operazioni di input‐output. E’ in questa libreria che sono definiti gli oggetti globali di I/O cout, cerr e cin e che risultano collegati ai dispositivi standard di I/O stdout, stderr e stdin. Per utilizzare questi cout, cerr e cin occorre includere l'header‐file: <iostream>.

Nella libreria iostream le operazioni di I/O vengono gestite in modo indipendente dal dispositivo effettivamente utilizzato  e che può essere un device fisico, un file o un’area di memoria come ad esempio una stringa.Le istruzioni di I/O vengono strutturate seguendo una particolare astrazione detta “stream” (flusso) che rappresenta un "qualcosa" da o verso cui "fluisce" una sequenza di bytes.

Un oggetto stream può essere visto come un’“entità" da cui estrarre (input), o inserire (output) dei dati.

36A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Overload degli operatori di flussoEsercizi sulle classi (1°parte)

… overload degli operatori di flusso << e >> …Gli operatori di scorrimento << e >> sono operatori binari. Producono lo scorrimento a destra / sinistra dei bit del primo operando (left‐operand) in quantità pari al valore indicato nel  right‐operand.

Shift a sinistra

Dentro la libreria iostream sono definite due classi globali, ostream e istream, corrispondenti agli stream di input e output. Queste due classi sovraccaricano gli operatori di scorrimento << e >>, dandogli la funzione di stampare e leggere dati.

In questa libreria vengono create due istanze delle classi ostream e istream: cout (Console Output) e cin (Console Input)  che vengono usate per stampare su schermo e leggere da tastiera. 

Nello stream l'operazione di output viene identificata mediante un'operazione di inserimento del dato (right operand) da scrivere nell'oggetto cout (left operand): 

cout << dato;

mentre l'operazione di input mediante un'operazione di estrazione del dato da leggere (rightoperand) dall'oggetto cin.

cin >> dato;

37A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Overload degli operatori di flussoEsercizi sulle classi (1°parte)

Vediamo ora come estendere gli operatori di flusso anche ai tipi astratti in modo che l‘istruzione:

Prima di procedere dobbiamo fare due precisazioni:1) Abbiamo posto come right‐operand dell’operatore di flusso l’istanza Dato della nostra classe A.L’operando a sinistra dell’operatore di flusso è invece un’istanza istream o ostream (cin e cout), diversa dalla classe a cui appartiene Dato, quindi sarà necessario lavorare su funzioni friend.

cout << dato;

… overload degli operatori di flusso << e >> …

2) Nell’implementazione della funzione‐operatore dobbiamo individuare anche il tipo di valore che essa dovrà restituire.

In C++ una chiamata del tipo:

è lecita per il fatto che il valore restituito dall’overloading dell’operatore di scorrimento << è nuovamente l’oggetto cout. 

cout << 5 << endl << “ciao”;

generi a  video la stampa dei valori assunti dai membri di Dato (dove Dato è un'istanza di una classe A).

38A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Overload degli operatori di flussoEsercizi sulle classi (1°parte)

… overload degli operatori di flusso << e >> 

un’ulteriore esecuzione semplifica progressivamente l’istruzione

cout << 5 << endl << “ciao”;

l’esecuzione di cout << 5 restituisce lo stesso cout per cui ottengo:

cout << endl << “ciao”;

cout << “ciao”;cout << endl << “ciao”;

In questo modo l’operazione si semplifica progressivamente:

Quindi il valore restituito dalla funzione di overload sarà il riferimento allo stream passato come argomento alla stessa. Inoltre il parametro della funzione‐operatore relativo allo stream deve essere passato come referencevisto che si deve lavorare sempre su quella particolare istanza.

I prototipi delle nostre due funzioni saranno quindi:

friend ostream& operator<< (ostream&, Dato);

Possiamo adesso passare all’implementazione dell’esercizio 2 sfruttando l’overloading degli operatori.

friend istream& operator>> (istream&, Dato&);

39A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2 – Soluzione alternativaEsercizi sulle classi (1°parte)

Complesso Complesso::somma(Complesso addendo) {

return Complesso (reale + addendo.reale, immag + addendo.immag); }

Complesso Complesso::operator+(Complesso addendo) {

return Complesso (reale + addendo.reale, immag + addendo.immag); }

Partendo dall’implementazione della somma mediante la funzione‐membro “convenzionale” …

… implemento l’overloading dell’operatore somma (+)

SOLUZIONE ALTERNATIVA

Utilizzando l’implementazione della funzione stampa() …

void Complesso::stampa() {if ( (reale!=0) || (immag==0) )

cout << reale;if (immag!=0) {

if ((immag > 0) && (reale!=0)) cout << "+";if (immag!=1) cout << immag;cout << "i";

}}

… scrivo l’overloading dell’operatore di flusso <<ostream& operator<<(ostream &output , Complesso numero) {

if ( (numero.reale!=0) || (numero.immag==0) )output << numero.reale;

if (numero.immag!=0){

if ((numero.immag > 0) && (numero.reale!=0)) output << "+";if (numero.immag!=1) output << numero.immag;output << "i";

}return output;

}

40A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2 – soluzione alternativaEsercizi sulle classi (1°parte)

int main() {Complesso n1, n2(3.5, 4);n1.stampa();n1 = n1.somma(n2);cout << " + ";n2.stampa();cout << " = ";n1.stampa();cout << endl;system("pause");return 0;

}

Partendo dal main() originale …

… riscrivo il nuovo main()

SOLUZIONE ALTERNATIVA

Al termine la nuova definizione della classe Complesso diventa:

istream& operator>>(istream& input , Complesso& numero){

cout << "Parte reale: ";input >> numero.reale;cout << "Parte immaginaria: "; input >> numero.immag;return input;

}

Complesso::Complesso() {cout << "Parte reale: ";cin >> reale;cout << "Parte immaginaria: "; cin >> immag;

}

Riprendendo l’implementazione del costruttore di default …

… effettuo l’overloading dell’operatore di flusso >>

int main() {Complesso n1, n2(3.5, 4);cin >> n1;cout << n1; n1 = n1 + n2;cout << " + " << n2 << " = " << n1 << endl;system("pause");return 0;

}

class Complesso {public:

. . .Complesso();Complesso somma(Complesso addendo);void stampa();. . .

};

class Complesso {public:

. . .Complesso operator+(Complesso addendo);friend ostream& operator<<(ostream &output, Complesso numero); friend istream& operator>>(istream& input, Complesso& numero);. . .

};

41A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2 – soluzione alternativaEsercizi sull’uso delle classi (1°parte)Soluzione completa …

/*************************************************************************** Nome: lab1-complesso-bis.c ** Autore: Alessandro Saetti ** Data: 6/4/10 ***************************************************************************/

#include <iostream>#include <stdlib.h>using namespace std;

class Complesso {public:Complesso();Complesso(float r, float i);Complesso operator+(Complesso addendo);friend ostream& operator<<(ostream &output , Complesso numero);

// Agisce come funzione globale (le passo esplicitamente l'oggetto su // cui operare) ma puo' accedere ai membri privati dell'oggettofriend istream& operator>>(istream& input , Complesso& numero);

private:float reale, immag;

};

42A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2 – soluzione alternativaEsercizi sull’uso delle classi (1°parte)… soluzione completa …

/* Nome: Complesso::Complesso* Scopo: Costruttore di default della classe complesso* Input: -* Output: -*/

Complesso::Complesso() {reale = 0;immag = 0;

} /* Nome: Complesso::Complesso* Scopo: Costruttore alternativo della classe complesso* Input: float r: la parte reale del numero complesso* float i: la parte immaginaria del numero complesso* Output: -*/

Complesso::Complesso(float r, float i) {reale = r;immag = i;

} /* Nome: Complesso::operator+* Scopo: Somma un numero complesso al numero complesso rappresentato * dall'oggetto* Input: Complesso addendo: il numero complesso da sommare

43A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2 – soluzione alternativaEsercizi sull’uso delle classi (1°parte)… soluzione completa …

* Output: Restituisce la somma tra i due numeri complessi* Nota: operator e' una parola chiave per il sovraccaricamento degli operatori*/

Complesso Complesso::operator+(Complesso addendo) {return Complesso(reale + addendo.reale, immag + addendo.immag);

}/* Nome: Complesso::operator<<* Scopo: Stampa il numero complesso * Input: ostream &output: Un flusso di dati* Complesso numero: Il numero complesso da stampare* Output: Il flusso di dati da stampare*/

ostream& operator<<(ostream &output , Complesso numero) {if ( (numero.reale!=0) || (numero.immag==0) )

output << numero.reale;if (numero.immag!=0) {

if ((numero.immag > 0) && (numero.reale!=0)) output << "+";if (numero.immag!=1) output << numero.immag;

output << "i";}

return output;}

44A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2 – soluzione alternativaEsercizi sull’uso delle classi (1°parte)… soluzione completa …

/* Nome: Complesso::operator>>* Scopo: Acquisisce un numero complesso * Input: ostream &output: Un flusso di dati* Complesso numero: Il numero complesso da inizializzare con i dati * acquisiti* Output: Il flusso di dati in cui salvare i dati*/

istream& operator>>(istream& input , Complesso& numero){

cout << "Parte reale: ";input >> numero.reale;cout << "Parte immaginaria: "; input >> numero.immag;return input;

}

/* Nome: main* Scopo: Gestione dei numeri complessi* Input: -* Output: 0 se il programma termina correttamente*/

45A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 2 – soluzione alternativaEsercizi sull’uso delle classi (1°parte)… soluzione completa.

int main() {

Complesso n1, n2(3.5, 4);cin >> n1;

cout << n1; n1 = n1 + n2;

cout << " + " << n2 << " = " << n1 << endl;system("pause");return 0;

}

46A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizi sulle classi (2º parte)3. Definire la classe studente (matricola, nome, cognome) con

– Un metodo che inizializza i dati dello studente (matricola, nome e cognome) con dati acquisiti da tastiera;

– Un metodo che visualizzi i dati dello studente.Sfruttando la classe precedente, definire la classe aula (gruppo di studenti) con

– Un costruttore che azzera in numero di studenti nel gruppo;– Un metodo che visualizza i dati degli studenti nel gruppo;– Un metodo che rimuove dal gruppo lo studente avente un numero di

matricola pari ad un intero acquisito da tastiera;– Un metodo che inserisce un nuovo studente nel gruppo.Scrivere un programma C++ che, sfruttando le classi precedentemente definite, supporti (tramite un menù di opzioni) l’aggiunta, la rimozione e la visualizzazione dei dati di studenti da un’aula.

47A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizi sulle classi (2º parte)Definire la classe studente (matricola, nome, cognome) con

– Un metodo che inizializza i dati dello studente (matricola, nome e cognome) con dati acquisiti da tastiera;

– Un metodo che visualizzi i dati dello studente.Sfruttando la classe precedente, definire la classe aula (gruppo di studenti) con

– Un costruttore che azzera in numero di studenti nel gruppo;

– Un metodo che visualizza i dati degli studenti nel gruppo;

– Un metodo che rimuove dal gruppo lo studente avente un numero di matricola pari ad un intero acquisito da tastiera;

– Un metodo che inserisce un nuovo studente nel gruppo.Scrivere un programma C++ che, sfruttando le classi precedentemente definite, supporti (tramite un menù di opzioni) l’aggiunta, la rimozione e la visualizzazione dei dati di studenti da un’aula.

48A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 3Esercizi sulle classi (2°parte)

/*************************************************************************** Nome: casa3-studente.c ** Autore: Alessandro Saetti ** Data: 6/4/10 ***************************************************************************/

#include <iostream>

/** Nome: main* Scopo: Gestione di un gruppo di studenti* Input: -* Output: 0 se il programma termina correttamente*/

int main() {

return 0;}

Impostiamo la solita struttura iniziale  di un programma C, aggiungendo eventuali commenti

// Definizione classe

// Menu per gestire le chiamate ai metodi// fornite dalla classe AULA

Definire la classe studente (matricola, nome, cognome) con– Un metodo che inizializza i dati dello studente (matricola, nome e cognome) con dati acquisiti da tastiera;– Un metodo che visualizzi i dati dello studente.

Sfruttando la classe precedente, definire la classe aula (gruppo di studenti) con– Un costruttore che azzera in numero di studenti nel gruppo;– Un metodo che visualizza i dati degli studenti nel gruppo;– Un metodo che rimuove dal gruppo lo studente avente un numero di matricola pari ad un intero acquisito da tastiera;– Un metodo che inserisce un nuovo studente nel gruppo.

Scrivere un programma C++ che, sfruttando le classi precedentemente definite, supporti (tramite un menù di opzioni) l’aggiunta, la rimozione e la visualizzazione dei dati di studenti da un’aula.

Non aggiungiamo #include <stdlib.h> poiché non ci serve usare system(“Pause”) per sospendere l’esecuzione del nostro programma.Infatti  implementeremo un menù di opzioni che resta in attesa della scelta dell’utente.

49A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 3Esercizi sulle classi (2°parte)Definire la classe studente (matricola, nome, cognome) con

– Un metodo che inizializza i dati dello studente (matricola, nome e cognome) con dati acquisiti da tastiera;– Un metodo che visualizzi i dati dello studente.

Sfruttando la classe precedente, definire la classe aula (gruppo di studenti) con– Un costruttore che azzera in numero di studenti nel gruppo;– Un metodo che visualizza i dati degli studenti nel gruppo;– Un metodo che rimuove dal gruppo lo studente avente un numero di matricola pari ad un intero acquisito da tastiera;– Un metodo che inserisce un nuovo studente nel gruppo.

Scrivere un programma C++ che, sfruttando le classi precedentemente definite, supporti (tramite un menù di opzioni) l’aggiunta, la rimozione e la visualizzazione dei dati di studenti da un’aula.

‐ il metodo stampa() che visualizza i dati dello studente, …

/* Nome: Studente::stampa* Scopo: Stampa i dato dello studente* Input: -* Output: -*/

void Studente::stampa() {cout << matricola << " " << nome << " " << cognome << " " << endl;

}

/* Nome: Studente::Studente* Scopo: Costruttore di default della classe Studente* Input: -* Output: -*/

Studente::Studente() {strcpy(nome, "");strcpy(cognome, "");matricola = 0;

}

Implementiamo:‐ il costruttore di default(quello senza argomenti) per la classe studente, …

50A.A. 2012/2013

Per la gestione dell’I/O utilizziamo gli oggetti globali di I/O cin e cout abbinati agli operatori di flusso << e >>.

Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 3Esercizi sulle classi (2°parte)

/* Nome: Studente::inserisci* Scopo: Inizializza i dati dello studente * con valori acquisiti da tastiera* Input: -* Output: -*/

void Studente::inserisci() {cout << "Inserisci matricola: ";cin >> matricola; cout << "Inserisci nome: ";cin >> nome;cout << "Inserisci cognome: ";cin >> cognome;

}

Definire la classe studente (matricola, nome, cognome) con– Un metodo che inizializza i dati dello studente (matricola, nome e cognome) con dati acquisiti da tastiera;– Un metodo che visualizzi i dati dello studente.

Sfruttando la classe precedente, definire la classe aula (gruppo di studenti) con– Un costruttore che azzera in numero di studenti nel gruppo;– Un metodo che visualizza i dati degli studenti nel gruppo;– Un metodo che rimuove dal gruppo lo studente avente un numero di matricola pari ad un intero acquisito da tastiera;– Un metodo che inserisce un nuovo studente nel gruppo.

Scrivere un programma C++ che, sfruttando le classi precedentemente definite, supporti (tramite un menù di opzioni) l’aggiunta, la rimozione e la visualizzazione dei dati di studenti da un’aula.

‐ il metodo per inserire un nuovo studente …/* Nome: Studente::restituisciMatricola* Scopo: Restituisce la matricola dello studente* Input: -* Output: la matricola dello studente*/

int Studente::restituisciMatricola() {return matricola;

}

La funzione membro restituisceMatricola() restituisce il contenuto della variabile membro privata contenente la matricola. Questo metodo viene utilizzato dalla funzione membro elimina() della classe Aula che definiremo successivamente

class Studente {public:

Studente();void inserisci();void stampa();int restituisciMatricola();

private:char nome[DIM1];char cognome[DIM1];int matricola;

};

Possiamo quindi definire la classe studente

51A.A. 2012/2013

/* Nome: Aula::Aula* Scopo: Costruttore di default * della classe Aula* Input: -* Output: -*/ Aula::Aula() {

n = 0; }

/* Nome: Aula::stampa* Scopo: Stampa i dati del* gruppo degli studenti* Input: -* Output: -*/ void Aula::stampa() {

int i;for (i = 0; i < n; i++)

aula[i].stampa();}

Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 3Esercizi sulle classi (2°parte)Definire la classe studente (matricola, nome, cognome) con

– Un metodo che inizializza i dati dello studente (matricola, nome e cognome) con dati acquisiti da tastiera;– Un metodo che visualizzi i dati dello studente.

Sfruttando la classe precedente, definire la classe aula (gruppo di studenti) con– Un costruttore che azzera in numero di studenti nel gruppo;– Un metodo che visualizza i dati degli studenti nel gruppo;– Un metodo che rimuove dal gruppo lo studente avente un numero di matricola pari ad un intero acquisito da tastiera;– Un metodo che inserisce un nuovo studente nel gruppo.

Scrivere un programma C++ che, sfruttando le classi precedentemente definite, supporti (tramite un menù di opzioni) l’aggiunta, la rimozione e la visualizzazione dei dati di studenti da un’aula.

Implementiamo quindi la classe Aula ‐ il costruttore di default …

Implementiamo: ‐ il metodo che stampa gli studenti presenti in una istanza di tipo aula …

/* Nome: Aula::aggiungi* Scopo: Aggiungi uno studente al* gruppo degli studenti* Input: -* Output: -*/ void Aula::aggiungi() {

aula[n++].inserisci();}

‐ il metodo che consente di aggiungere un nuovo studente alla classe (in fondo) …

class Aula {public:

Aula();void aggiungi();void elimina();void stampa();

private:Studente aula[DIM2];int n;

};/* Nome: Aula::elimina* Scopo: Elimina uno studente dal gruppo* degli studenti* Input: -* Output: -*/ void Aula::elimina() {

int i, m;cout << "Inserisci matricola: ";cin >> m;for (i = 0; i < n; i++) {

if (aula[i].restituisciMatricola() == m) {aula[i] = aula[n-1];n = n - 1;

}}

}

‐ la funzione membro che chiede la matricola dello studente da eliminare. L’eliminazione avviene 

sostituendo lo studente da eliminare con l’ultimo in 

elenco

52A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 3Esercizi sulle classi (2°parte)Definire la classe studente (matricola, nome, cognome) con

– Un metodo che inizializza i dati dello studente (matricola, nome e cognome) con dati acquisiti da tastiera;– Un metodo che visualizzi i dati dello studente.

Sfruttando la classe precedente, definire la classe aula (gruppo di studenti) con– Un costruttore che azzera in numero di studenti nel gruppo;– Un metodo che visualizza i dati degli studenti nel gruppo;– Un metodo che rimuove dal gruppo lo studente avente un numero di matricola pari ad un intero acquisito da tastiera;– Un metodo che inserisce un nuovo studente nel gruppo.

Scrivere un programma C++ che, sfruttando le classi precedentemente definite, supporti (tramite un menù di opzioni) l’aggiunta, la rimozione e la visualizzazione dei dati di studenti da un’aula.

Impostiamo ilmain() con un menù opzioni che richiama le funzionalità rese disponibili dai metodi della classe Aula.

int main() {Aula eip;int x;do {

cout << "1. Stampa\n2. Inserisci\n3. Elimina\n0. Esci\n-> "; cin >> x;switch(x) {

case 1: eip.stampa();break;

case 2: eip.aggiungi();break;

case 3: eip.elimina();break;

}} while(x != 0);return 0;

}

53A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 3Esercizi sull’uso delle classi (2°parte)Soluzione completa…

/*************************************************************************** Nome: casa3-studente.c ** Autore: Alessandro Saetti ** Data: 6/4/10 ***************************************************************************/

#include <iostream>#include <string.h>#define DIM1 50#define DIM2 100#define TRUE 1#define FALSE 0

using namespace std;

class Studente {public:

Studente();void inserisci();void stampa();int restituisciMatricola();

private:char nome[DIM1];char cognome[DIM1];int matricola;

};

54A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 3Esercizi sull’uso delle classi (2°parte)…Soluzione completa…

class Aula {public:

Aula();void elimina();void stampa();

private:Studente aula[DIM2];int n;

};/* Nome: Studente::Studente* Scopo: Costruttore di default della classe Studente* Input: -* Output: -*/

Studente::Studente() {strcpy(nome, "");strcpy(cognome, "");matricola = 0;

}/* Nome: Studente::inserisci* Scopo: Inizializza i dati dello studente con valori acquisiti da tastiera* Input: -* Output: -*/

55A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 3Esercizi sull’uso delle classi (2°parte)

…Soluzione completa…

void Studente::inserisci() {

cout << "Inserisci matricola: ";cin >> matricola; cout << "Inserisci nome: ";cin >> nome;cout << "Inserisci cognome: ";cin >> cognome;

}/* Nome: Studente::stampa* Scopo: Stampa i dato dello studente* Input: -* Output: -*/

void Studente::stampa() {

cout << matricola << " " << nome << " " << cognome << " " << endl; }/* Nome: Studente::restituisciMatricola* Scopo: Restituisce la matricola dello studente* Input: -* Output: la matricola dello studente*/

int Studente::restituisciMatricola() {

return matricola;}

56A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 3Esercizi sull’uso delle classi (2°parte)…Soluzione completa…

/* Nome: Aula::Aula* Scopo: Costruttore di default della classe Aula* Input: -* Output: -*/

Aula::Aula() {n = 0;

}/* Nome: Aula::stampa* Scopo: Stampa i dati del gruppo degli studenti* Input: -* Output: -*/

void Aula::stampa() {int i;for(i = 0; i < n; i++) aula[i].stampa();

}/* Nome: Aula::aggiungi* Scopo: Aggiungi uno studente al gruppo degli studenti* Input: -* Output: -*/

void Aula::aggiungi(){

aula[n++].inserisci();}

57A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 3Esercizi sull’uso delle classi (2°parte)…Soluzione completa… /* Nome: Aula::elimina

* Scopo: Elimina uno studente dal gruppo degli studenti* Input: -* Output: -*/

void Aula::elimina() {int i, m;

cout << "Inserisci matricola: ";cin >> m;

for (i = 0; i < n; i++) {if (aula[i].restituisciMatricola() == m) {

aula[i] = aula[n-1];n = n - 1;

}}

}/* Nome: main* Scopo: Gestione di un gruppo di studenti* Input: -* Output: 0 se il programma termina correttamente*/

int main(){

Aula eip;int x;

58A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizio 3Esercizi sull’uso delle classi (2°parte)…Soluzione completa…

do {cout << "1. Stampa\n2. Inserisci\n3. Elimina\n0. Esci\n-> "; cin >> x;switch(x) {

case 1: eip.stampa();break;

case 2: eip.aggiungi();break;

case 3: eip.elimina();break;

}} while(x != 0);return 0;

}

59A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizi sulle classi (per casa)1. Definire la classe dei numeri razionali con

• Un costruttore che inizializza il denominatore con un intero casuale compreso tra 1 e 10 ed il numeratore con un numero casuale compreso tra 1 ed il denominatore;

• Un costruttore che inizializzi il numero razionale della classe con due dati interi.

• Un metodo che produca il numero reale pari al numero razionale della classe;

• Un metodo che inizializzi il numero razionale della classe con interi acquisiti da tastiera, riducendo il numero razionale ai minimi termini;

• Un metodo che produca il numero razionale (ridotto ai minimi termini) ottenuto sommando il numero razionale della classe con un secondo numero razionale;

Scrivere un programma C++ che, sfruttando la classe precedentemente definita, inizializzi e visualizzi un vettore di 10 numeri razionali ed infine visualizzi la somma dei 10 numeri razionali.

60A.A. 2012/2013Docente: A. Saetti Fondamenti di Programmazione - Università degli Studi di Brescia

Esercizi sulle classi (per casa)2. Modificare la soluzione dell’esercizio precedente

affinché il programma sia in grado di gestire sia studenti della laurea triennale (matricola, nome e cognome) che studenti della laurea specialistica (matricola, nome, cognome e voto di laurea) utilizzando le seguenti indicazioni:

• Definire una gerarchia di classi (triennale e specialistica sono classi derivate della classe studente);

• Sfruttare il polimorfismo per virtualizzare i metodi della classe studente per l’acquisizione e la visualizzazione dei dati degli studenti della laurea triennale e degli studenti della laurea specialistica.