Traduzione Ita 1 (1)

Sommario

  • Introduction:
    • Classes and objects
    • Coding style guidelines for classes
    • Inheritance
    • Generic programming & templates
    • STL
    • Exceptions
    • Resource Management
    • Design patterns
      • Adapter
      • Observer
      • Factory

Introduzione

  • Perchè uno sviluppo verso l’OO?
    • Una strutture migliorata del software è + semplice per :
      • Capire
      • Mantenere
      • Valorizzare
      • Il riutilizzo di component software e schemi(modules)
      • Potenziare un componente già esistente
      • Creare nuovi componenti più generalizzabili.
  • Programmazione strutturata vs approccio OO
    • L’analisi e il design della programmazione strutturata si concentra principalmente su una struttura procedurale e, in quanto tale la funzionalità relativa agli stessi dati è stata spesso diffusa attraverso il sistema di software.
    • L’approccio object oriented si concentra su lo strutturare il sistema intorno ai dati incapsulandoli all’interno di oggetti in modo tale che tutte le funzionalità in relazione con tali dati sono, almeno in teoria, contenuti all’interno degli oggetti stessi.
  • Concetti chiave dell’OO
    • L’idea principale: incapsulare i dati all’interno di oggetti
      • Data Abstraction: poichè ora i dati sono visti non più in termini di puri “data values” ma differentemente in termini delle operazioni che possiamo effettura su di essi.
      • ADT’s(Abstract Data Type), information hiding: poichè i dettagli dell’implementazione dei data format e il modo in cui tali operazioni sono effettivamente implementate sono nascoste da altro codice che utilizza un oggetto.
      • C++ classes: più ovvia facilità usata per implementare delle “data abstraction”
      • Ereditarietà (generalizzazione)
        • La gerarchia delle classi e l’ereditarietà: alcune classi di oggetti sono generalizzazioni di altre classi più specifiche di oggetti e così ha senso porre funzionalità generali in ciò che noi chiamiamo classe base e permettere funzionalità più specifiche da poter essere messe in classi derivate dalla classe base. Si dice che le classi derivate ereditano(o estendono) le funzionalità della classe base.
      • Il polimorfismo: possiamo usare differenti tipi di oggetti nello stesso modo è ciò che il software system, in questo caso il C++, elaborerà per noi quale funzionalità dovrebbe in verità essere invocate in realtà a seconda dell’effettivo tipo di oggetto che è coinvolto per un particolare utilizzo.
        • Le stesse operazioni su differenti cassi/oggetti: Operatori aritmetici che possono essere applicati sia con interi che con float, sebbene la reale implementazione dell’aritmetica e abbastanza diversa.
        • Funzioni virtuali
        • L’operatore overloading
        • In C++ il polimorfismo è sostenuto dall’uso di oggetti che sono chiamate funzioni virtuali come pure per mezzo di un sovraccarico ulteriore di operatori standard.

Oggetti

  • Un oggetto è come una variabile commune: è come una reale istanza di una entità software che detiene reali informazioni, ad esemio riguardo a qualcosa del mondo reale.
    • Contiene informazioni
    • È la realizzazione Software di alcune “cose” del mondo.
    • Si possono applicare delle operazioni su di essi.

Classi

  • Un classe è(come) un tipo:
    • Una astrazione di una serie di oggetti che si comportano in modo identico: tiene insieme l’implementazione dei dati e le operazioni.
    • Definise l’implementazione interna, le operazioni.
    • Si possono creare(istanziare) oggetti da una classe, esattamente come per un built-in type (int o float), un tipo definito (di)dall’utente usando la facilitazione della classe può allora essere istanziato in oggetti o variabili.
    • Le classi aiutano a organizzare il codice e a ragionare sui programmi.
    • Una classe è la rappresentazione di un’idea, un concetto, in forma di codice. Un oggetto di una classe rappresenta un particolare esempio dell’idea nel codice.
    • Senza le classi, un lettore del codice dovrebbe indovinare/supporre le relazioni tra i data-items e le funzioni – le classi rendono tali relazioni esplicite e comprensibile dai compilatori.
    • Con le classi, gran parte della struttura di alto livello del tuo programma si riflette nel codice, non semplicemente nei commenti.
  • I metodi dell’OO.
    • I metodi dell’OO sono una serie di tecniche per analizzare, decomporre e modularizzare l’architettura dei software systems.
    • In generale, i sistemi si evolvono e le funzionalità cambiano, ma gli oggetti(e le classi degli oggetti) tendono a rimanere stabili nel tempo.
    • Il paradigma dell’OO influenza l’intero processo di sviluppo del software. Procede attraverso una serie di frasi, sebbene i limiti siano spesso sfocati/confusi.

OO Software Development

  • OO Analysis:
    • La funzionalità, classi e le loro realzioni richieste nell’identificazione: spesso usa(l’ Analysis) strumenti(tools) presi dall’UML(Unified Modelling Language) come ad esempio i diagrammi di classe e l’uso di “cases” . (such as class diagrams and use cases)
  • OO Design:
    • Specificare la gerarchia tra le classi, le interfacce delle classi e il loro comportamento. Gli UML tools come diagrammi di classe, di iterazione e di stato possono essere usati nel Design di tipo OO.
  • OO Programming:
    • ImpIementare un OO design in un linguaggio di programmazione OO: in questa fase il codice è effettivamente scritto, testato e integrato con altro codice.
  • OOA
    • Object-oriented analysis (OOA) applica le tecniche di object-modeling per analizzare le esigenze funzionali del sistema.
    • L’OOA guarda al centro del problema, con il fine di produrre un modello concettuale dell’informazione che c’è nella zona che è stata analizzata e ne carpisce le necessità.
    • I modelli dell’Analysis non considerano nessun impedimento di implementazione che potrebbe esistere.

OOD

  • Object-oriented design (OOD) elabora i modelli di analisi per produrre una descrizione specifica dell’implementazione.
  • Durante lo sviluppo dell’OOD si creano astrazioni e meccanismi necessari per incontrare le richieste di comportamento del sistema(systems’) fissati durante l’OOA.
  • I concetti nei modelli dell’analisi sono mappati nelle classi di implementazione. Il risultato è un modello della(del dominio della) soluzione, una dettagliata descrizione di come il system debba essere costruito..
  • OOD è relativamente independente dal linguaggio di programmazione utilizzato.
  • OOA si concentra su ciò che il sistema esegue, OOD invece su come il sistema lo esegue
  • Gli obiettivi del Design
    • Creare software che sia semplice da cambiare ed estendere, ovvero flessibile.
    • Decoporre il sistema in moduli, determinando le relazioni tra essi, per esempio identificando le dipendenze e le forme di comunicazione.
    • Le classi, il lo uso, l’ereditarietà, la composizione.
    • Raggiungere un Software altamente coeso, poco accoppiato.
  • Object Oriented Programming
    • Object-oriented programming (OOP) è concentrato principalemente sul linguaggio di programmazione e nelle questioni di implementazione del software.
    • OOP è un paradigma di programmazione che usa “oggetti” – strutture dati che consistono di dati e metodi insieme alle loro interazioni – per progettare applicazioni e programmi per il computer.
    • Un programma object-oriented può esser visto come un insieme di oggetti che interagiscono, in opposizione al modello strutturale della programmazione, in cui un programma è visto come una lista di compiti(task/ subroutines) da eseguire.
  • Procedural Programming vs. OOP
    • Un programma può esser visto come una sequenza di chiamate procedurali. Il main program è responsabile di passare dati alle varie singole chiamate, i dati sono processati da delle procedure.
    • Un programma può esser visto come una rete di oggetti interagenti tra loro, ciascuno autosufficiente.

History of C++

  • C++ fu inventato da Bjarne Stroustrup, circa negli anni 80’ .
  • C++ non è semplicemente un linguaggio di programmazione Object-Oriented, è un multi- paradigm
  • ISO Standard in 1998 (C++98), aggiornato nel 2003

C++ and C

  • C++ è un diretto discendente del C che conserva quasi tutto il C come sottoinsieme.
  • C++ fornisce un controllo maggiore sui tipi rispetto al C e supporta un più ampio range di stili di programmazione di quanto non faccia il C.
  • C++ sub-languages
    • C++ può essere considerato come un federazione di linguaggi; i principali sotto linguaggi sono:
      • C: poichè il C++ supporta tutte le tecniche di programmazione supportate dal C
      • Object Oriented C++: con classi, incapsulazione, ereditarietà, polimorfismo, etc.
      • Template C++: generic programming in C++

Makefiles

  • Progetti più ampi richiederanno l’uso di Makefile.
  • Un makefile è un file di testo a cui si fa riferimento per mezzo del comando make che descrive la costruzione di obiettivi(eseguibili e librerie), e contiene informazioni come le dipendenze source- level e le dipendenze dell’ordine di costruzione.
  • Eclipse è un IDE che tratta questi makefiles.

Classes and objects

  • Perchè astrarre?
    • Aiuta a dare un modello al problema, separando i dettagli necessari da quelli inutili.
    • Vogliamo ottenere una separazione tra:
      • le operazioni eseguite sui dati
      • La rappresenzazione delle strutture dati e l’implementazione degli algoritmi.
    • L’astrazione è lo stutturare un problema nebuloso e indefinito in precisi schemi definindo i dati e le operazioni(accoppiate).
  • ADT (Abstract Data Type)
    • Un ADT è un’individuazione di un set di dati e di un set di operazioni (chiamata interfaccia dell’ADT) che possono essere eseguite sui dati.
    • È un’astrazione nel senso che è indipendente dalle varie concrete implementazioni.
    • Quando un programma è realizzato, l’ADT è rappresentato da un’interfaccia, che maschera una corrispondente implementazione. Gli utenti di un ADT sono concentrati sull’interfaccia, non sull’implementazione, che può cambiare nel futuro.
  • Why encapsulation ?
    • Il principio di nascondere le strutture dati usate e di fornire solo una meglio definita interfaccia è detto incapsulazione.
    • La separazione di strutture dati e operazioni e le restrizioni per cui si può accedere alla struttura dato solo attraverso l’interfaccia(ben definita), permette di scegliere la struttura dati appropriata per l’ambiente del’applicazione.
  • Why classes?
    • Una classe è una reale rappresentazione di un ADT: essa fornisce dettagli implementativi per la struttura dati utilizzata e le operazioni.
    • Richiama l’importante distinzione tra una classe e un’oggetto:
      • Una classe è una rappresentazione astratta di una serie di oggetti che si comportano identicamente.
      • Oggetti(ovvero variabili) sono istanziati dalle classi.
      • Le classi definiscono le proprietà e il comportamento di un insieme di oggetti.
  • Classes and objects
    • Una classe è un’implementazione di un ADT. Definisce gli attributi e i metodi che implementano la struttura dati e le operazioni dell’ADT rispettivamente.
    • Un oggetto è un’istanza di una classe. Può essere identificato univocamente col suo nome e definisce uno stato, il quale è rappresentato dai valori dei suoi attributi in un particolare momento.
    • Il comportamento di un oggetto è definito da un insieme di metodi che possono essere applicati su di esso.
  • Procedural programming
    • C’è una divisione tra i dati e le operazioni su di essi.
    • Il centro della programmazione procedurale è di scomporre i compiti di un programma in una serie di variabili, strutture dati e subroutines.
    • Quando si programma in C ci concentriamo su le strutture dati e le funzioni.
  • OO programming
    • Nella programmazione object-oriented ci si concentra nello scomporre un programma in oggetti e le iterazione tra gli oggetti.
    • Un oggetto è associato a dati e operazioni su tali dati, ad esempio:
      • L’oggetto “oven” ha un dato interno che rappresenta la temperatura e un’operazione attraverso la quale è posibile impostare una nuova temperatura.
  • Why C++ classes ?
    • Una classe C++ può prevedere l’information hiding:
      • Nasconde la rappresentazione interna dei dati
      • Naconde i dettagli implementativi delle operazioni.
    • La classe agisce come una scatola nera, fornendo un servizio ai propri clienti, senza rivelare il proprio codice che potrebbe essere usato in modo errato.
  • Il principio dell’Open-Closed
    • L’incapsulazione è una tecnica chiave per seguire il principio dell’Open-Closed:
      • Le classi dovrebbero essere aperte all’estenzione ma chiuse per la modifica.
      • Vogliamo permettere cambiamenti al sistema, ma senza richiedere una modifica del codice esistente.
      • Se una classe ha un particolare comportamento, codificato nella maniera che preferiamo, se nessuno può cambiare il codice della classe l’abbiamo chiuso a modifiche.
      • Ma, se per qualche ragione, dobbiamo estendere tale comportamento, possiamo lasciar estendere la classe di cui dobbiamo sovrascrivere il metodo e fornirle nuove funzionalità. La classe è aperta all’estensione.
      • Vedremo come l’ereditarietà e la composizione ci aiuterà a seguire tale principio.
  • Class identification
    • Identificare oggetti reali o entità del mondo come potenziali classi di oggetti software.
    • L’approccio consueto è quello di pensare agli oggetti del mondo reale che esistono nel dominio dell’applicazione che sta per essere programmata. Invece di pensare ai processi che devono essere eseguiti, come facevamo solitamente nella programmazione procedurale, pensiamo invece alle cose del mondo reale.
    • Identificare gruppi di oggetti che si comportano similarmente, che possono essere implementati come classi.
    • Le classi sono descrizioni per gli oggetti.
    • Ritardare le decisioni circa i dettagli implementativi, come per esempio ciò per cui i dati e le operazioni si applicheranno agli oggetti fino a quando non abbiamo una chiara idea di quali classi di oggetti saranno richieste.
    • L’iniziare a modellare una classe identificando le classi candidate - una lista iniziale di classi dalle quali emergeranno le classi del vero Design.
    • Una regola generale per identificare le classi candidate: identificare il nome e le frasi sostantivo, i verbi(azioni),e gli aggettivi(attributi) dai casi e dalla descrizione del problema.
    • Ci sono metodi più formali per identificare(ad esempio CRC cards, use cases) e rappresentare(e.g. UML) le classi.
  • Single responsibility principle
    • Ogni oggetto nel suo sistema dovrebbe avere una singola responsabilità, e tutti i servizi dell’oggetto dovrebbero essere concentrati sul esternare questa unica responsabilità.
    • Una classe dovrebbe avere solo un motivo per cambiare.
    • Una responsabilità può essere definite come una ragione buona per cambiare.
    • È un concetto collegato alla coesione.
    • Per esempio considera un modulo che compila e stampa un report: il contenuto del report può cambiare, il formato del report può cambiare.
    • Il principio della singola responsabilità dice che questi due aspetti del problema sono davvero due responsabilità separate, e dovrebbero dunque stare in classi separate o moduli.
    • Non accoppiare due cose che cambiano per ragioni differenti in momenti differenti.
  • SRP: example
    • Ecco un semplice test per capire se una classe segue l’SRP: per ogni metodo della classe scrivi una riga che dice
      • Adatta la grammatica e la sintassi e leggila ad alta voce.Ha senso?
      • Se non lo ha probabilmente il metodo appartiene ad un’altra classe.
    • Use common sense!
    • Applica il metodo alla classe Automobile:
      • Siamo ancora molto lontani dall’avere macchine che si guidano da sole(abbiamo bisogno di un autista)
      • Sicuramente non si autocambieranno le gomme o si autolaveranno (ma avranno bisogno di un meccanico)
      • Pensa bene al significato dei metodi: getOil signiica semplicemente che la macchina ha un sensore.
  • C++ Classes
    • Una classe C++ estende il concetto di strutture C
    • Mette insieme gruppi di variabili(attributi o dati membro) che possono essere referenziati usando un nome collettivo e un identificatore simbolico.
    • Può avere funzioni (metodi o funzioni membro) che operano nel contesto della classe
    • Definisce un tipo di dato: possiamo crearne un’istanza(detto oggetto).
  • Class definition
    • Use the keyword class, ad esempio:

classStackclass Stack
{
bool push(data value);
bool pop(data* pValue);
void init(int size);
int TOS;
data* buffer;
int size;
}; // do NOT forget the ; !

A C stack implementation

structstackstruct stack
{
int TOS;
data *buffer;
int size;
};

boolpush(structstackptr,datavalue)bool push(struct stack *ptr, data value) {…}
boolpop(structstackptr,datapValue)bool pop(struct stack *ptr, data *pValue) {…}

  • Access level
    • Tutti i membri di una struct sono visibili non appena c’è un riferimento alla struttura, mentre in una classe è possibile differenziare il tipo di accesso come pubblico, privato o protetto(l’accesso di default è impostato su privato).
    • Possiamo progettare meglio l’ “interfaccia” della classe, cioè decidere ciò che può essere nascosto e ciò che può essere visibile nella classe(incapsulazione). Possiamo disaccoppiare le classi.
  • Access levels
    • Public: un membro pubblico è visibile a tutti quanti i quali abbiano l’indirizzo o il riferimento all’oggetto.
    • Private: un membro privato è visibile solo ai metodi della classe in cui è definito.
    • Protected: un membro protetto è visibile soltanto ai metodi della classe in cui è definito, e in tutte le classi derivate(fino in fondo col meccanismo dell’ereditarietà).
    • Example:

classStackclass Stack
{
public:
bool push(data value);
bool pop(data* pValue);
void init(int size);
private:
int TOS;
data* buffer;
int size;
};

  • Access levels: regola generale
    • Usa sempre un controllo di accesso esplicito
    • Non avere dati membro(attributi) pubblici
    • Utilizza metodi pubbllici per set/get i loro valori(dei dati membro).
    • Diversi IDEs possono creare questi metodi automaticamente.
  • Method implementation
    • Di solito i metodi sono definiti(implementati) nei files .cpp: Aggiungi il nome della classe davanti al metodo ad esempio:

boolstack::push(datavalue)bool stack::push(data value)
{
// code to implement the method
}

  • Possiamo implementarli anche nell’header(inline), ma di solito questo viene fatto solo se questi sono molto corti(ad esempio 5 o 7 righe)
  • Attributes
    • Un metodo può accedere agli attibuti della classe: gli attributi sono visibili all’interno dei metodi.
    • Ciò riduce di molto la complessità delle interfaccie del C: paragona il l’implementazione C++ con quella del C.
    • Gli attributi mantengono lo “stato” degli oggetti
    • Gli attributi sono una sorta di contesto condiviso dai metodi(è per questo che le interfacce sono più semplici)
    • Comunque, i metodi sono più accoppiati con gli attributi.
    • Vale la pena pagare questo prezzo se le classi sono state progettate per avere responsabilità comuni.
  • Argument passing
    • In C il meccanismo di passaggio avviene “per valore”: il valore dei parametri attuali(arguments) viene copiato nei parametri formali.
    • Una funzione usa la copia dei valori per effetture i suoi calcoli.
    • Noi dobbiamo usare puntatori per simulare un passaggio “per riferimento” .
    • In C++ possiamo passare parametri anche per riferimento.
  • Pass by reference
    • Un riferimento è essenzialemnte un sinonimo in senso che non c’è una copia del dato passata nei parametri attuali(actual argument).
    • Si indica con il simbolo e commerciale & che segue il tipo del parametro attuale(base).
    • In C++, la chiamata per riferimento e la chiamata simulata in stile C usando puntatori sono simili, ma non ci sono puntatori coinvolti esplicitamente: non c’è bisogno di deferenziare il parametro attuale(argument).

void add(int a, int b, int& sum)
{
sum = a + b;
}

intmain()int main()
{
int i = 1;
int j = 2;
int total = 0;
cout << “total: “ << total << endl;
add( i, j, total);
cout << “total: “ << total << endl;
}

void f(int m, double& x)
{
m = 100;
x = 3.14
}

intmain()int main()
{
int s = 50;
double t = 2.72;
f(s,t);
return 0;
}

1) 2) 3)

  • Un riferimento può essere specificato come const: la funzione/metodo non può modificare il contenuto della variabile.
    • Passa grandi strutture dati che non devono essere modificate come riferimento costante(è veloce)
  • Reference variables
    • È possible avere un riferimento variabile, ma deve sempre tenere un riferimento valido, e quindi deve essere inizializzato quando viene creato.

intx;int x;

int& y=x; // reference

y=2;//alsoxismodifiedy=2; // also x is modified

int& z; // Error: doesn’t compile ! Why ?

intz;//pointerint *z; // pointer

z = &x; // & on the left is different from & on the right of =

z=3;//xismodified*z = 3; // x is modified

  • Overloading
    • Possiamo definire più di un metodo con lo stesso nome e tipo di ritorno, ma con differenti(in numero e tipo) parametri(signature). Tale metodo è detto sovraccaricato(overloaded).
    • Comunemente usato per fornire una versione alternativa di funzioni per essere usata in differenti situazioni.
    • La stessa operazione astratta può avere differenti implementazioni concrete.
    • Il compilatore creerà un differente segmento di codice e un simbolo(attraverso lo storpiamento(mangling) del nome) ottenuto estendendo il nome del metodo con suffissi relativi ai tipi di parametri.
    • Non possiamo semplicemente cambiare il valore di ritorno: il compilatore dovrebbe sempre controllare il tipo della variabile dove mettiamo il valore.. e che succede se noi ce ne liberiamo?
  • Operator overloading
    • È possibile sovraccaricare anche gli operatori, non solo i metodi(nella vita reale + è un operatore usato per interi, numeri reali, numeri complessi..)
    • Sovraccaricare gli operatori solo quando ha davvero senso
    • Ad esempio sovraccaricare l’ == per comparare stringhe,( do not overload * for strings…)
    • Alcuni linguaggi OO non permettono il sovraccaricamente degli operatori, in particolare il Java.
    • Gli operatori sono sovraccaricati nel senzo che gli oggetti si comportano come tipi primitivi.
    • Non possono essere creati nuovi operatori, possono essere modificate solo le funzionalità di operatori già esistenti.
    • Se tu sovraccarichi il + non devi aspettarti che il += sia dato automaticamente! Va ridefinito anche tale operatore.
    • Spesso gli operatori sono semplicemente friend… (more later)

classArrayclass Array
{
public:
Array(int size); // constructor
bool operator ==(const Array& right) const; //the method can’t modify anything
// … other members
private:
int size;
int* data; // pointer to first element of array
};

bool Array::operator==(const Array& right) const
{
if ( size != right.size ) // start checking the size of the arrays
return false;
// then check the whole content of arrays
for ( int i=0; i < size; i++ ) {
if ( data[i] != right.data[i] )
return false;}
return true; // both size and content are equal
}

  • Type checking
    • C++ ha un controllo molto più severo sui tipi rispetto al C: dipente dal cast dei parametri (depending on the parameter cast you determine the method that is executed !)
    • Ad esempio: Fai il cast dei puntatori a vuoto quando li assigni ad altri puntatori(in C questo compila lo stesso).(cast void pointers when assigning them to other pointers, in C it compiles).
  • Object creation
    • Una volta che una classe è definita possiamo creare le istanze(oggetti) da essa, come si fa per le variabili dei tipi base.
    • La creazione può essere statica(sullo stack) o dinamica(sull’heap)
    • Il codice dei metodi è rappresentato nel segmento di codice, condiviso tra tutte le istanze di una classe.
    • Ogni oggetto ha un indirizzo della funzione che implementa i metodi.
  • Dynamic object creation
    • È molto simile all’utilizzo delle funzioni di malloc/free, ma sintatticamente semplificato, usando il new e il delete:

stacksPtr;stack* sPtr;

sPtr=newstack;sPtr = new stack;

deletesPtr;delete sPtr;

  • Constructors
    • È una funzione membro che sarà invocata quando un oggetto di tale classe è creato. Non restituisce valore.
    • Ha sempre lo stesso nome della classe. In generale i costruttori compiono una sorta di inizializzazione di un oggetto. Se non viene definito un costruttore ne viene generato uno di default, senza alcun parametro.
    • È comune sovraccaricare una funzione costruttore (cioè fornirne più versioni) cosicchè l’oggetto possa essere creato in differenti maniere.
    • Considera come oggetti di un nuovo tipo possano essere creati e quali costruttori sono necessari.
    • Se non è definito un costruttore il compilatore ne genera uno di default che non prende parametri.
    • Il costruttore di default è solitamente invocato senza parentesi, ad esempio nell’esempio precedente: sPtr = new stack;
    • Se una classe ha qualche costruttore ma non ne ha uno di default la sua creazione sarà costretta a situazioni gestite dai costruttori, ad esempio

classBclass B
{
public:
B(int i) { … }
};

Bb1;//illegalB b1; // illegal

Bb3(123);//okB b3(123); // ok

  • C’è una maniera compatta e compiler-friendly per inizializzare gli attributi in un costruttore:

classstackclass stack
{
protected:
int TOS;
data *buffer;
int size;
public:
stack(int s) : TOS(0), size(s), buffer(new data[s]) {…}
}

  • I costruttori sono pubblici (di solito, ma non necessariamente)
    • Se non vogliamo che una classe sia istanziata possiamo dichiarare un costruttore come protetto. Possiamo istanziare le classi derivate(se il loro costruttore è pubblico).
    • In altri casi possiamo dichiarare un costruttore come private.
    • Il suo utilizzo è tipicamente collegato ai metodi static.
  • Explicit constructors
    • I costruttori in C++ che hanno solo un parametro eseguono implicitamente una conversione del tipo, ad esempio: se passi un intero quando un costruttore si aspetta un parametro puntatore a stringa, il compilatore aggiungerà il codice che deve convertire l’intero in un puntatore a stringa.
    • Puoi aggiungere esplicitamente al costruttore una declaration per prevenire queste conversioni implicite.
    • Dichiarare un costruttore che ha più parametri che devono essere espliciti, poichè in tal caso questi costruttori non possono prendere parte alle conversioni implicite.
    • Comunque, l’eplicitare avrà un effetto se un costruttore ha più parametri e tutti eccetto uno dei parametri hanno assegnato un valore di default.
    • Explicit constructors: example

classAclass A
{
public:
A();
};

classBclass B
{
public:
explicit B(int x=0, bool b=true);
};

classCclass C
{
public:
explicit C(int x);
};

voiddoSomething(BobjB);void doSomething(B objB);

BobjB1;B objB1;

doSomething(bObj1);//OKdoSomething( bObj1 ); // OK

BobjB2(28);//OK,bargissettodefaultB objB2( 28 ); // OK, b arg is set to default

doSomething(28);//BAD:weneedaBobj,andwedonotallowimplicit//conversiondoSomething(28); // BAD: we need a B obj, and we do not allow implicit // conversion

doSomething(B(28));//OKdoSomething(B(28)); // OK

doSomething(foo);//BAD,thanksthecompilerfornotallowingitdoSomething(“foo”); // BAD, thanks the compiler for not allowing it

  • È preferibile utilizzare costruttori espliciti(c’è anche una Google C++ guideline for it)
    • Mentre progetti un tipo(ovvero una classe) pensa quali conversioni dovrebbero essere permesse:
    • Dovresti scrivere un tipo di funzione di conversione o un costruttore non esplicito(con un solo parametro)?
  • Destructors
    • È un metodo con lo stesso nome della classe preceduto da ~ , ad esempio: ~stack();
    • Niente parametri, niente valori di ritorno, nessun overload
    • Viene chiamato automaticamente quando un oggetto viene distrutto.
    • Dovrebbe mantenere un sistema che lavori in modo corretto(housekeeping).
  • C’tor and D’tor

classstackclass stack
{
protected:
int TOS;
data* buffer;
int size;
public:
stack(int s);
~stack();
//..}

// C’tor allocates memory

stack::stack(ints)stack::stack(int s)
{
TOS=0;
size=s;
buffer = new data[size];
}

// D’tor has to release memory

stack:: stack()stack::~stack()
{
delete(buffer);
}

  • Come si usano metodi e attribute?
    • I membri di una classe possono essere referenziati analogamente ai membri di uno struct:

<var>.membername<var>.member_name

->member_name

  • Ma tenendo conto della loro visibilità, definita dal livello di accesso. Ad esempio:

stackS;stack S;

stackpS;stack *pS;

ps = &S;

S.push(3);

pS->push(8);

  • Self reference
    • Un oggetto può far riferimento a se stesso tramite la parola this.
    • Un oggetto usa implicitamente this quando si riferisce a un metodo o ad un attributo.

stack::stack(ints)stack::stack(int s)
{
TOS=0;
}

stack::stack(int s)
{
this->TOS=0;
this->size=s;
this->buffer = new data[this->size];
}

  • L’uso di this è essenziale quando un oggetto deve passare un riferimento a se stesso ad un altro oggetto.
    • Una tipica applicazione è il callback(richiamo): l’oggetto A dà un riferimento a se stesso che sarà utilizzato dall’oggetto B per invocare un metodo sull’oggetto A.
    • This è usato per implementare schemi di inversione di responsabilità: l’oggetto A non chiama l’oggetto B per eseguire un’operazione ma lascia che l’oggetto B chiami l’oggetto A.

class observer;

class subject;

class observer
{
public:
void update(subject* pSubj);
int getState() {return state;}
private:
int state;
};

class subject
{
public:
subject(observer* pObs);
void setState(int aState);
int getState() {return state;}
private:
int state;
observer* pObs;
};

observer::update(subject* pSubj)
{
if ( … ) // possible condition that starts an update
this->state = pSubj->getState();
}

subject::subject(observer* pObs)
{
this->pObs = pObs;
}

subject::setState(int aState)
{
this->state = aState;
this->pObs->update( this );
}

int main()
{
subject* pSubj;
observer*