2. Il sistema dei tipi del C++
• Uno degli obiettivi principali del C++ è
permettere al programmatore di creare tipi
personalizzati e usarli come se fossero offerti
dal linguaggio
• Il sistema dei tipi del C++ comprende
– Tipi predefiniti (predefined)
– Tipi composti (composite)
– Tipi definiti dall’utente (user defined)
– Tipi classe (class types)
3. I costruttori di tipi
• A partire dai tipi predefiniti si possono creare
nuovi tipi, che aggiungono proprietà speciali ai
tipi predefiniti
– Const (visto)
– Reference (visto)
– Pointer (ancora da vedere)
• A questi si aggiungono costruttori di tipi definiti
interamente dall'utente
– struct (eredità del C, poco usato in C++)
– Class
4. Tipi composti aggregati
• Variabili omogenee: sequenza finita /
indefinita
– ARRAY (sequenza predefinita), VECTOR (sequenza
indefinita)
• Variabili disomogenee: tipi classe
– STRUCT (record)
– CLASS (oggetti con dati e funzioni dichiarati e
definiti assieme)
4
5. Esigenza
• Nella progettazione dei dati, spesso capita di
prevedere informazioni connesse in gruppi logici:
– Parole in un testo e loro frequenza
– Indirizzo, composto da via n. civico città
– Dati dell'utente: username, password, email
• In questi casi, piuttosto che variabili separate, si
usa un costruttore di tipo che definisce un gruppo
logico di variabili correlate, detto "record"
(ovvero: scheda, registrazione)
6. Il costruttore di tipo record
• Record (o struct): memorizzano aggregazioni di
dati di diversa natura
• Ciascun dato è chiamato “campo” o dato membro
(member):
struct {
string via;
int numero;
int CAP;
string citta;
} indirizzo;
//
//
//
//
1o
2o
3o
4o
campo:
campo:
campo:
campo:
stringa
intero
intero
stringa
nome della variabile record
• indirizzo è un record formato da quattro
campi di vario tipo
7. Uso dei record
• Il record (o struct) è una sorta di “contenitore” di campi
di tipo disomogeneo
• Il record raggruppa dati più semplici
– Ne rende più ordinata la gestione, evitando confusioni
• I campi del record non sono accessibili individualmente
– L'accesso avviene mediante il record a cui appartengono
– Si utilizza l'operatore . come metodo di accesso ai campi
• indirizzo.citta
– Con gli iterator si usa l'operatore -> : iter->member
– I nomi dei campi sono identificatori “locali” all’interno di
una variabile di tipo record, da usarsi come suffissi
8. Operazioni su campi dei record
• Le operazioni che sono definite sono le stesse
applicabili sui tipi dei campi
• Assegnamento ai campi del record:
indirizzo.via = "Ponzio";
indirizzo.numero 34;
indirizzo.CAP 20133;
indirizzo.citta = "Milano";
• Accesso (leggere, scrivere…):
– cout << indirizzo.numero;
– cin >> indirizzo.CAP;
9. Assegnamento di record
• Dati due record identici (cioè dichiarati insieme) è lecito
assegnare globalmente il primo al secondo
struct … / campi / rec1, rec2;
•
è lecito scrivere:
rec2 rec1;
• tutti i campi di rec1 sono ordinatamente copiati nei campi
corrispondenti di rec2.
• Se i due record sono diversi (anche solo per l’ordine dei
campi) l’assegnamento è privo di senso !
• Memento: l’assegnamento “diretto” tra array è vietato
– deve avvenire elemento per elemento
• Ma…. Diventa possibile tra membri array di una struct!
13. Tipi definiti dall'utente
• I record sono un caso esemplare in cui un tipo ha una
struttura definita dal programmatore
• Tuttavia è un tipo "anonimo"
• C e C++ forniscono un modo per dare un nome a un tipo
• Esempio:
• typedef int intero;
• intero numero;
•
è equivalente a:
• int numero;
• È la definizione di un sinonimo
– Il nuovo tipo intero eredita le caratteristiche (valori e
operazioni) del tipo di partenza int
14. Costruttore di record (struct)
•
•
•
Definizione di un tipo tipo data per le date:
typedef struct {
int giorno;
int mese;
int anno;
} data;
Dichiarazione di variabili di tipo data:
data oggi, domani, dopodomani;
Altro esempio:
typedef struct {
char nome[20];
char cognome[20];
data nato_il;
char nato_a[15];
char codice_fiscale[16];
int stipendio;
} dipendente;
dipendente piero;
15. Esempi d'uso
• Si possono dichiarare le variabili:
dipendente persona1, persona2;
• E modificare i dati membro:
persona1.stipendio + (persona1.stipendio 10) 100;
persona2.stipendio + (persona2.stipendio 10) 100;
• Anche innestati:
persona2.nato_il.giorno = 15; // NB: accede a campo
giorno del campo data di dipendente
16. Progettazione dei dati
• Esempio vendite di libri
– Si vuole costruire un programma che gestisca le vendite di
libri
• Ogni libro è caratterizzato da un codice ISBN
– Il programma deve gestire per ogni libro il numero totale di
copie vendute, il ricavo totale e medio
– L'utente inserisce sequenzialmente i dati di vendita per i
diversi libri, il programma aggrega i dati per ciascun codice
ISBN e stampa il dato aggregato
– Deve quindi essere possibile:
• Inserire e stampare i dati di un libro
• Sommare più dati di vendita relativi allo stesso libro
• Stampare i dati di vendita aggregati relativi a un libro
17. Suddivisione del programma
• Un file di libreria (Sales_item.h) conterrà la
definizione del tipo che rappresenta il dato di
vendita: Sales_item
• Definiamo ora Sales_item come struct, cioè un
tipo definito dall'utente che comprende dati, ma
non le operazioni relativi al dato di vendita
– Campi: codice ISBN, copie vendute, ricavo
• Il programma principale importa e usa Sales_item
come se fosse un tipo predefinito
– Sales_item item; // dichiara una var. di tipo Sales_item !
19. Programma principale
#include <iostream>
#include <string>
#include "Sales_data.h"
using namespace std;
int main()
{
Sales_data data1, data2;
// code to read into data1 and data2
double price = 0; // price per book, used to calculate total revenue
// read the first transactions: ISBN, number of books sold, price per book
cin >> data1.bookNo >> data1.units_sold >> price;
// calculate total revenue from price and units_sold
data1.revenue = data1.units_sold * price;
// read the second transaction
cin >> data2.bookNo >> data2.units_sold >> price;
data2.revenue = data2.units_sold * price;
// check whether data1 and data2 have the same ISBN, if so print the sum of data1 and data2
if (data1.bookNo == data2.bookNo) {
unsigned totalCnt = data1.units_sold + data2.units_sold;
double totalRevenue = data1.revenue + data2.revenue;
// print: ISBN, total sold, total revenue, average price per book
cout << data1.bookNo << " " << totalCnt << " " << totalRevenue << " ";
if (totalCnt != 0)
cout << totalRevenue/totalCnt << endl;
else
cout << "(no sales)" << endl;
} else {
}
}
return 0; // indicate success
cerr << "Data must refer to the same ISBN"
return -1; // indicate failure
<< endl; // transactions not for same ISBN