|
|
| << | < | > | >> |IndicePREFAZIONE XI Lo scopo di questo libro xi La metodologia di insegnamento xii L'apprendimento attraverso il codice xii L'accesso al World Wide Web xiii Obiettivi xiii Il codice e gli esempi xiii Figure e immagini xiii Consigli e suggerimenti xiii Conclusioni xiv Esercizi di autovalutazione xiv Esercizi xiv Indice analitico xv Panoramica del libro xv Le sezioni "Pensare in termini di oggetti" xxi CAPITOLO 1: INTRODUZIONE Al COMPUTER, A INTERNET E AL WEB 1 1.1 Introduzione 1 1.2 Che cos'è un computer? 2 1.3 La struttura del computer 3 1.4 I primi sistemi operativi 4 1.5 I personal computer, i sistemi distribuiti e i sistemi client/server 5 1.6 Internet e il World Wide Web (WWW) 5 1.7 I linguaggi macchina, assembly e ad alto livello 6 1.8 Il C e il C++: un po' di storia 7 1.9 La libreria standard del C++ 8 1.10 Java: un po' di storia 9 1.11 FORTRAN, COBOL, Pascal, Ada 9 1.12 Basic, Visual Basic, Visual C++, C# e .NET 10 1.13 Una tendenza fondamentale: la tecnologia degli oggetti 11 1.14 Gli elementi fondamentali di un tipico ambiente C++ 12 1.15 Alcune considerazioni generali sul C++ e sul nostro corso 15 1.16 La prima applicazione C++ 16 1.17 Pensare in termini di oggetti: introduzione alle tecniche orientate agli oggetti e a UML (Unified Modeling Language)TM 21 UML sul Web 26 Letture consigliate 26 Esercizi di autovalutazione 26 Risposte agli esercizi di autovalutazione 26 1.18 Conclusioni 27 Esercizi di autovalutazione 27 Risposte agli esercizi di autovalutazione 28 Esercizi 28 CAPITOLO 2: INTRODUZIONE ALLA PROGRAMMAZIONE C++ 31 2.1 Introduzione 31 2.2 Il primo programma C++: visualizzare una linea di testo 31 2.3 Modifica del primo programma C++ 35 2.4 Un altro programma C++: l'addizione di due numeri interi 36 2.5 La memoria: concetti fondamentali 41 2.6 I calcoli aritmetici 43 2.7 Prendere decisioni: gli operatori relazionali e di uguaglianza 46 2.8 Pensare in termini di oggetti: esame delle specifiche del sistema ATM [Progetto opzionale] 51 Esercizi di autovalutazione 58 Risposte agli esercizi di autovalutazione 58 2.9 Conclusioni 58 Esercizi di autovalutazione 59 Risposte agli esercizi di autovalutazione 60 Esercizi 62 CAPITOLO 3: INTRODUZIONE ALLE CLASSI E AGLI OGGETTI 67 3.1 Introduzione 67 3.2 Classi, oggetti, dati e funzioni membro 68 3.3 Sommario degli esempi del capitolo 69 3.4 Definizione di una classe con una funzione membro 70 3.5 Definizione di una funzione membro con un parametro 73 3.6 I dati membro e le funzioni set e get 77 3.7 Inizializzazione degli oggetti tramite i costruttori 84 3.8 Memorizzazione di una classe in un file separato per favorire il riutilizzo 88 3.9 Separare l'interfaccia dall'implementazione 93 3.10 Convalida dei dati con le funzioni set 99 3.11 Pensare in termini di oggetti: identificare le classi del sistema ATM [Progetto opzionale] 104 Esercizi di autovalutazione 110 Risposte agli esercizi di autovalutazione 111 3.12 Conclusioni 112 Esercizi di autovalutazione 112 Risposte agli esercizi di autovalutazione 113 Esercizi 113 CAPITOLO 4: LE STRUTTURE DI CONTROLLO: PRIMA PARTE 115 4.1 Introduzione 115 4.2 Gli algoritmi 115 4.3 Lo pseudocodice 116 4.4 Le strutture di controllo 117 4.5 L'istruzione di selezione if 121 4.6 La struttura di selezione if...else 122 4.7 L'istruzione iterativa while 128 4.8 Formulazione degli algoritmi: l'iterazione controllata da un contatore 129 4.9 Formulazione degli algoritmi: l'iterazione controllata da un valore sentinella 136 4.10 Formulazione degli algoritmi: le istruzioni di controllo nidificate 147 4.11 Gli operatori di assegnamento 153 4.12 Gli operatori di incremento e decremento 153 4.13 Pensare in termini di oggetti: identificare gli attributi delle classi del sistema ATM [Progetto opzionale] 156 Esercizi di autovalutazione 161 Risposte agli esercizi di autovalutazione 161 4.14 Conclusioni 161 Esercizi di autovalutazione 162 Risposte agli esercizi di autovalutazione 163 Esercizi 165 CAPITOLO 5: LE STRUTTURE DI CONTROLLO: SECONDA PARTE 175 5.1 Introduzione 175 5.2 Concetti fondamentali dell'iterazione controllata da un contatore 176 5.3 L'istruzione di iterazione for 177 5.4 Esempi di istruzioni for 182 5.5 L'istruzione iterativa do...while 187 5.6 L'istruzione di selezione multipla switch 189 5.7 Le istruzioni break e continue 199 5.8 Gli operatori logici 201 5.9 Confondere l'operatore di uguaglianza == con l'operatore di assegnamento = 206 5.10 Riepilogo dei concetti fondamentali della programmazione strutturata 207 5.11 Pensare in termini di oggetti: identificare gli stati e le attività degli oggetti nel sistema ATM [Progetto opzionale] 212 Esercizi di autovalutazione 214 Risposte agli esercizi di autovalutazione 216 5.12 Conclusioni 217 Esercizi di autovalutazione 217 Risposte agli esercizi di autovalutazione 218 Esercizi 219 CAPITOLO 6: LE FUNZIONI E LA RICORSIONE 225 6.1 Introduzione 225 6.2 I componenti di un programma C++ 226 6.3 Le funzioni matematiche della libreria standard 227 6.4 Definizione di funzioni con più argomenti 229 6.5 Prototipi di funzione e conversione forzata degli argomenti 234 6.6 I file di intestazione della libreria standard del C++ 237 6.7 La generazione di numeri casuali 239 6.8 I giochi d'azzardo e la parola riservata enum 245 6.9 Le informazioni di memorizzazione 249 6.10 Le regole di visibilità 252 6.11 La sequenza delle chiamate di funzioni e i record di attivazione 256 6.12 Funzioni che hanno una lista di parametri vuota 259 6.13 Le funzioni in linea 261 6.14 I riferimenti e il passaggio di parametri per riferimento 263 6.15 Gli argomenti di default 268 6.16 L'operatore unario di risoluzione dello scope 270 6.17 La ridefinizione delle funzioni 271 6.18 I template di funzione 274 6.19 Il concetto di ricorsione 277 6.20 Un altro esempio di ricorsione: la serie di Fibonacci 281 6.21 Ricorsione o iterazione? 284 6.22 Pensare in termini di oggetti: identificare le operazioni delle classi del sistema ATM [Progetto opzionale] 287 Esercizi di autovalutazione 293 Risposte agli esercizi di autovalutazione 294 6.3 Conclusioni 294 Esercizi di autovalutazione 294 Risposte agli esercizi di autovalutazione 297 Esercizi 300 CAPITOLO 7: GLI ARRAY 311 7.1 Introduzione 311 7.2 Gli array 312 7.3 Come si dichiara un array 314 7.4 Alcuni esempi di array 314 7.5 Il passaggio di un array a una funzione 331 7.6 La classe GradeBook con un array per memorizzare i voti 336 7.7 Ricerca lineare negli array 343 7.8 Ordinamento degli array con l'ordinamento per inserzione 345 7.9 Gli array multidimensionali 347 7.10 La classe GradeBook con un array bidimensionale 350 7.11 Introduzione al template vector della libreria standard del C++ 358 7.12 Pensare in termini di oggetti: la collaborazione tra gli oggetti del sistema ATM [Progetto opzionale] 363 Esercizi di autovalutazione 370 Risposte agli esercizi di autovalutazione 370 7.13 Conclusioni 371 Esercizi di autovalutazione 372 Risposte agli esercizi di autovalutazione 373 Esercizi 374 Esercizi sulla ricorsione 384 Esercizi su vector 384 CAPITOLO 8: PUNTATORI E STRINGHE 385 8.1 Introduzione 385 8.2 Come si dichiarano e si inizializzano i puntatori 386 8.3 Gli operatori di manipolazione dei puntatori 387 8.4 La chiamata per riferimento con argomenti di tipo puntatore 390 8.5 Utilizzo di const con i puntatori 394 8.6 L'algoritmo di ordinamento per selezione con il passaggio per riferimento 401 8.7 Gli operatori sizeof 405 8.8 L'aritmetica dei puntatori 408 8.9 La correlazione tra puntatori e array 411 8.10 Gli array di puntatori 415 8.11 Un programma per mescolare e distribuire carte da gioco 416 8.12 I puntatori a funzione 422 8.13 Introduzione alla manipolazione delle stringhe 428 8.13.1 Caratteri e stringhe: concetti fondamentali 428 8.13.2 Le funzioni di libreria per le stringhe 430 8.14 Conclusioni 439 Esercizi di autovalutazione 440 Risposte agli esercizi di autovalutazione 442 Esercizi 444 Sezione speciale: costruite il vostro computer 447 Ulteriori esercizi sui puntatori 452 Esercizi sulla manipolazione di stringhe 457 Sezione speciale: esercizi avanzati sulla manipolazione di stringhe 459 Un progetto di manipolazione di stringhe complesso 462 CAPITOLO 9: LE CLASSI: PRIMA PARTE 463 9.1 Introduzione 463 9.2 La classe Time 464 9.3 L'ambito di visibilità a livello di classe e l'accesso ai membri di una classe 471 9.4 La separazione di interfaccia e implementazione 473 9.5 Le funzioni di accesso e di utilità 474 9.6 La classe Time: costruttori con argomenti di default477 9.7 I distruttori 483 9.8 Quando sono chiamati i costruttori e i distruttori 483 9.9 La classe Time e un sottile errore logico: restituire un riferimento a un dato membro private 487 9.10 La copia di default membro a membro 490 9.11 La riusabilità del software 492 9.12 Pensare in termini di oggetti: programmazione delle classi del sistema ATM [Progetto opzionale] 493 Esercizi di autovalutazione 499 Risposte agli esercizi di autovautazione 499 9.13 Conclusioni 500 Esercizi di autovalutazione 501 Risposte agli esercizi di autovalutazione 502 Esercizi 502 CAPITOLO 10: LE CLASSI: SECONDA PARTE 505 10.1 Introduzione 505 10.2 Gli oggetti e le funzioni membro costanti 506 10.3 Il concetto di composizione: oggetti che diventano membri di altre classi 516 10.4 Le funzioni e le classi friend 523 10.5 Il puntatore this 527 10.6 L'allocazione dinamica della memoria: gli operatori new e delete 533 10.7 I membri static di una classe 535 10.8 Astrazione dei dati e mascheramento delle informazioni 542 10.8.1 Il tipo di dato astratto "array" 543 10.8.2 Il tipo di dato astratto "stringa" 544 10.8.3 Il tipo di dato astratto "coda" 544 10.9 Le classi container e gli iteratori 545 10.10 Le classi proxy 545 10.11 Conclusioni 549 Esercizi di autovalutazione 550 Risposte agli esercizi di autovalutazione 550 Esercizi 551 CAPITOLO 11: LA RIDEFINIZIONE DEGLI OPERATORI 553 11.1 Introduzione 553 11.2 La ridefinizione degli operatori: concetti fondamentali 554 11.3 Restrizioni 555 11.4 Le funzioni operatore come funzioni membro o funzioni globali 557 11.5 La ridefinizione degli operatori di inserimento/estrazione su stream 559 11.6 La ridefinizione degli operatori unari 562 11.7 La ridefinizione degli operatori binari 563 11.8 Progettazione della classe Array 564 11.9 Conversioni tra tipi diversi 577 11.10 Progettazione della classe String 578 11.11 La ridefinizione degli operatori ++ e -- 591 11.12 Progettazione della classe Date 593 11.13 La classe della libreria standard string 598 11.14 I costruttori explicit 602 11.15 Conclusioni 606 Esercizi di autovalutazione 606 Risposte agli esercizi di autovalutazione 606 Esercizi 607 CAPITOLO 12: L'EREDITARIETÀ 617 12.1 Introduzione 617 12.2 Le classi base e le classi derivate 619 12.3 I membri protected 622 12.4 Le relazione tra classe base e classi derivate 622 12.4.1 Creazione e utilizzo della classe CommissionEmployee 623 12.4.2 Creazione della classe BasePlusCommissionEmployee senza utilizzare l'ereditarietà 628 12.4.3 Creazione di una gerarchia di ereditarietà CommissionEmployee-BasePlusCommissionEmployee 634 12.4.4 La gerarchia di ereditarietà CommissionEmployee-BasePlusCommissionEmployee con i dati protected 640 12.4.5 La gerarchia di ereditarietà CommissionEmployee-BasePlusCommissionEmployee con i dati private 648 12.5 Utilizzo dei costruttori e dei distruttori nelle classi derivate 656 12.6 Ereditarietà di tipo public, protected e private 664 12.7 Il ruolo dell'ereditarietà nell'ingegneria del software 665 12.8 Conclusioni 667 Esercizi di autovalutazione 667 Risposte agli esercizi di autovalutazione 668 Esercizi 668 CAPITOLO 13: IL POLIMORFISMO 671 13.1 Introduzione 671 13.2 Esempi di polimorfismo 673 13.3 Le relazioni tra oggetti in una gerarchia di ereditarietà 674 13.3.1 Chiamata delle funzioni della classe base dagli oggetti di una classe derivata 674 13.3.2 Collegamento di puntatori a una classe derivata a oggetti della classe base 682 13.3.3 Chiamate alle funzioni membro della classe derivata attraverso puntatori alla classe base 683 13.3.4 Le funzioni virtuali 686 13.3.5 Riepilogo degli assegnamenti permessi tra oggetti e puntatori della classe base e delle classi derivate 692 13.4 I campi di tipo e le istruzioni switch 693 13.5 Le classi astratte e le funzioni virtuali pure 694 13.6 Progettazione di un libro paga elettronico 696 13.6.1 La classe base astratta Employee 697 13.6.2 La classe derivata concreta SalariedEmployee701 13.6.3 La classe derivata concreta HourlyEmployee 703 13.6.4 La classe derivata concreta CommissionEmployee 706 13.6.5 La classe derivata concreta indiretta BasePlusCommissionEmployee 708 13.6.6 Verifica dell'applicazione del polimorfismo 710 13.7 L'implementazione di polimorfismo, funzioni virtuali e binding dinamico [Sezione opzionale] 714 13.8 Progettazione di un libro paga elettronico utilizzando il polimorfismo e l'informazione sui tipi in fase di esecuzione con downcasting, dynamic_cast, typeid e type_info 719 13.9 I distruttori virtuali 723 13.10 Pensare in termini di oggetti: incorporare l'ereditarietà nel sistema ATM [Progetto opzionale]723 Esercizi di autovalutazione 730 Risposte agli esercizi di autovalutazione 730 13.11 Conclusioni 731 Esercizi di autovalutazione 732 Risposte agli esercizi di autovalutazione 732 Esercizi 732 APPENDICE A: PRECEDENZA E ASSOCIATIVITÀ DEGLI OPERATORI 735 APPENDICE B: L'INSIEME DEI CARATTERI ASCII 737 INDICE ANALITICO 739 |
| << | < | > | >> |Pagina XIPrefazione"Il più grande merito dei linguaggi è la chiarezza..." Galeno
Benvenuti nel mondo del C++! Il C++ è un linguaggio universalmente diffuso
per lo sviluppo di applicazioni industriali di grandi prestazioni. Crediamo che
questo libro, con i suoi materiali di supporto, contenga tutto ciò che serve a
docenti e studenti per intraprendere un'esperienza interessante e formativa nel
mondo del C++.
Lo scopo di questo libro Il Professor Harvey M. Deitel ha tenuto corsi universitari introduttivi sulla programmazione per 20 anni, puntando soprattutto a insegnare come sia possibile sviluppare programmi ben scritti e ben strutturati. Molti dei suoi insegnamenti riguardano i concetti fondamentali della programmazione, con particolare enfasi sull'utilizzo efficace delle strutture di controllo e sulla funzionalità. Questi argomenti vengono presentati all'interno di questo libro esattamente nel modo in cui il Professor Deitel li ha sempre proposti ai propri studenti universitari. Il nostro obiettivo era chiaro: offrire un testo sul C++ destinato ai corsi universitari a livello introduttivo, per quegli studenti che non hanno alcuna esperienza nell'ambito della programmazione, pur fornendo, allo stesso tempo, la completezza teorica e pratica richiesta ai tradizionali corsi avanzati di C++. Con questo proposito abbiamo scritto i due volumi C++ Fondamenti di programmazione e C++ Tecniche avanzate di programmazione; nell'insieme, un'opera assai completa su questo linguaggio. Un importante elemento caratterizzante il testo è UML (Unified Modeling Language), uno strumento di rappresentazione grafica dei sistemi che utilizziamo nell'analisi completa, dalla definizione all'implementazione, di un caso complesso di progettazione orientata agli oggetti. Tutti i diagrammi UML nel testo sono conformi allo standard UML 2.0. I diagrammi delle classi UML sono utilizzati per rappresentare graficamente le classi e le loro relazioni di ereditarietà mentre i diagrammi di attività UML sono utilizzati per rappresentare graficamente il flusso del controllo nelle istruzioni di controllo del C++. Alla fine dei primi sette capitoli, del capitolo 9 e del capitolo 13 troverete una sezione intitolata "Pensare in termini di oggetti", il cui scopo è presentare gradualmente la progettazione orientata agli oggetti utilizzando il linguaggio UML. UML è oggi lo schema più utilizzato per rappresentare graficamente i sistemi orientati agli oggetti. UML è un linguaggio grafico complesso e prevede numerose funzionalità, di cui noi vogliamo presentare soltanto un sottoinsieme. Le funzionalità che analizziamo servono per guidare il lettore nella sua prima esperienza di progettazione orientata agli oggetti come esperienza complementare alla comprensione dei concetti che iniziamo a presentare nel capitolo 1 e a implementare nel capitolo 3. Lo studio di questo progetto, che riguarda il software di gestione di un bancomat reale, ci accompagna per diversi capitoli fino alla sua implementazione, ed esitiamo quindi a chiamarlo soltanto un esercizio, perché è piuttosto un'esperienza di programmazione che si conclude solo con l'analisi del codice C++ completo. Potete trovare una presentazione dettagliata delle diverse sezioni che riguardano il progetto più avanti nella prefazione. Questo libro introduce i concetti e la terminologia base della tecnologia degli oggetti fin dal primo capitolo. Ciò porta gli studenti a "pensare in termini di oggetti" immediatamente e a padroneggiarli quindi maggiormente. La programmazione orientata agli oggetti non è per nulla banale ma scrivere programmi orientati agli oggetti è divertente e gli studenti possono avere risultati immediati. Il testo è corredato di numerosi esempi di programmi completi, che molto spesso estendono una classe introdotta precedentemente con nuovi concetti programmativi. Tra questi esempi possiamo menzionare le classi GradeBook (registro elettronico dei voti) nei capitoli 3-7, Time (per rappresentare gli orari) nei capitoli 9-10 ed Employee (dipendente aziendale) nei capitoli 12-13. Vengono inoltre presentati alcuni aspetti tecnici del linguaggio, che riguardano in particolar modo la sua implementazione. Il capitolo 3 include una discussione e un diagramma dettagliato del processo di compilazione e collegamento necessario a produrre un'applicazione eseguibile. Il capitolo 6 illustra dettagliatamente lo stack delle chiamate di funzione e i record di attivazione, per mostrare come il C++ tiene traccia della funzione correntemente eseguita, di come vengono memorizzate le variabili automatiche delle funzioni e di come viene restituito il controllo alla funzione chiamante. Il capitolo 13 contiene infine una spiegazione dettagliata del funzionamento "dietro le quinte" del polimorfismo, delle funzioni virtuali e del binding dinamico. In tal modo, oltre ad avere una maggiore consapevolezza di come possono essere implementate certe caratteristiche del linguaggio, lo studente viene sensibilizzato anche ai relativi problemi di efficienza che si vengono a creare. Il testo segue lo standard ANSI del C++; tenete presente che molte funzionalità previste nell'ANSI non sono implementate nelle versioni precedenti del C++. Per avere informazioni più dettagliate sul linguaggio vi conviene consultare il manuale di riferimento del vostro sistema o procurarvi una copia del documento INCITS/ISO/IEC 14882-2003 reperibile sul sito webstore.ansi.org/ansidocstore/default.asp. [...] Panoramica del libro Capitolo 1 – Introduzione: i computer, Internet e il WWW. Spiega cosa sono i computer, come funzionano e in che modo possono essere programmati. Il capitolo traccia brevemente la storia dello sviluppo dei linguaggi di programmazione, dai linguaggi macchina, ai linguaggi assembly fino ai linguaggi ad alto livello. Si parla anche dell'origine del C++. Il capitolo include un'introduzione agli ambienti di sviluppo tipici del C++, e prevede la descrizione passo-passo dell'esecuzione di un'applicazione C++ in ambiente Windows e Linux. Il capitolo introduce infine i concetti e la terminologia base della tecnologia degli oggetti e il linguaggio UML. Capitolo 2 – Introduzione alla programmazione C++. Fornisce una breve introduzione allo sviluppo di programmi in C++. Il capitolo introduce i non programmatori ai concetti e ai costrutti base della programmazione. I programmi di questo capitolo mostrano come visualizzare dati sullo schermo e come ottenere l'input dell'utente dalla tastiera. Il capitolo si conclude con un descrizione dettagliata dei processi decisionali e delle operazioni aritmetiche. Capitolo 3 – Introduzione alle classi e agli oggetti. Fornisce un'introduzione informale alle classi e agli oggetti, familiarizzando da subito gli studenti con gli oggetti. Vengono introdotti classi, oggetti, funzioni membro, costruttori e dati membro attraverso una serie di esempi del mondo reale e viene sviluppato un ambiente per il progetto di programmi orientati agli oggetti in C++ secondo i principi dell'ingegneria del software. Inizialmente vengono fornite le motivazioni al concetto di classe con un semplice esempio, quindi vengono presentati sette esempi di programmi completi e selezionati che mostrano la creazione e l'utilizzo delle classi definite dall'utente. Questi esempi costituiscono i primi passi del progetto di un'applicazione che rappresenta un registro elettronico dei voti (Grade Book) degli studenti per un corso. Il progetto viene sviluppato nei capitoli seguenti fino alla sua versione finale del capitolo 7. Il progetto per l'applicazione GradeBook mostra come si definisce una classe e come la si usa per creare degli oggetti, come si dichiarano e definiscono le funzioni membro della classe che implementano i suoi comportamenti, come si dichiarano i dati membro della classe che implementano gli attributi e come si invocano le funzioni membro di un oggetto. Viene inoltre presentata la classe string della libreria standard del C++ per creare un oggetto destinato a contenere il nome del corso cui il registro elettronico si riferisce. Nel capitolo vengono infine evidenziate le differenze tra dati membro di una classe e variabili locali di una funzione e viene spiegato come utilizzare un costruttore per inizializzare opportunamente i dati membro di un oggetto. Viene mostrato inoltre come favorire il riutilizzo del software separando la definizione della classe dal codice client (cioè la funzione main) che utilizza la classe e viene introdotto un altro importante principio dell'ingegneria del software: separare l'interfaccia dall'implementazione. Il capitolo include infine un diagramma dettagliato del processo di compilazione e di collegamento necessario a produrre un'applicazione eseguibile. Capitolo 4 – Le strutture di controllo: prima parte. Introduce il processo di sviluppo di programmi necessario a produrre classi utili. Questo capitolo mostra come ottenere un programma C++ funzionante a partire dalla definizione di un problema, utilizzando passi intermedi in pseudocodice. Il capitolo introduce le semplici istruzioni di controllo per la selezione (if e if ... else) e l'iterazione (while). Vengono esaminati i cicli controllati da un valore sentinella e quelli controllati da un contatore utilizzando la classe GradeBook del capitolo 3 e vengono introdotti gli operatori di assegnamento, incremento e decremento. Il capitolo include inoltre due versioni aggiornate della classe GradeBook del capitolo 3, che comprendono una funzione membro che utilizza istruzioni di controllo per calcolare la media dei voti degli studenti. Nella prima versione la funzione membro utilizza un ciclo controllato da un contatore per leggere 10 voti inseriti dall'utente e calcolarne la media. Nella seconda versione la funzione membro utilizza un ciclo controllato da un valore sentinella per leggere un numero arbitrario di voti inseriti dall'utente e visualizzare la media dei voti inseriti. Il capitolo utilizza i diagrammi di attività UML per rappresentare il flusso del controllo nelle diverse istruzioni di controllo. Capitolo 5 – Le strutture di controllo: seconda parte. Continua lo studio delle istruzioni di controllo del C++ con esempi delle istruzioni iterative for e do...while, l'istruzione di selezione switch e le istruzioni break e continue. Viene presentata una versione aggiornata della classe GradeBook che utilizza un'istruzione switch per contare il numero di occorrenze dei voti A, B, C, D e F inseriti dall'utente. I voti vengono letti con un ciclo controllato da un valore sentinella che modifica i dati membro che mantengono il conteggio dei diversi voti inseriti. Un'altra funzione membro della classe utilizza i dati membro per visualizzare un riepilogo dei voti. Il capitolo include una discussione sugli operatori logici. Capitolo 6 – Le funzioni e la ricorsione. Fornisce una descrizione dettagliata degli oggetti e delle loro funzioni membro. Vengono illustrate le funzioni della libreria standard e viene esaminata in dettaglio la modalità di costruzione di funzioni personalizzate. Le tecniche presentate in questo capitolo sono essenziali per creare programmi strutturati correttamente, e sono ancora più importanti nei programmi destinati a gestire problemi del mondo reale. Viene presentata la strategia del "divide et impera" come metodo efficace per risolvere problemi complessi, suddividendoli appunto in componenti più semplici, che interagiscono tra di loro. Il primo esempio del capitolo continua il progetto della classe GradeBook aggiungendo una funzione membro con più parametri. Gli studenti apprezzano in genere l'argomento della generazione dei numeri casuali e della simulazione, così come i giochi di dadi che fanno un utilizzo elegante delle strutture di controllo. Il capitolo illustra anche i cosiddetti "miglioramenti" apportati dal C++ al C, tra cui le funzioni inline, i parametri riferimento, gli argomenti di default, l'operatore unario di risoluzione dello scope, la ridefinizione delle funzioni e i template di funzione. Vengono inoltre presentati i passaggi di parametro per valore e per riferimento del C++ e una tabella riassuntiva dei file di intestazione che saranno utilizzati maggiormente nel corso del libro. Vengono inoltre discussi in modo dettagliato (con illustrazioni) lo stack delle chiamate di funzione e i record di attivazione, per spiegare come il C++ tiene traccia della funzione attualmente in esecuzione, di come sono memorizzate le variabili automatiche delle funzioni e di come viene gestita la restituzione del controllo alla funzione chiamante. Il capitolo fornisce un'introduzione rigorosa alla ricorsione e include una tabella che ricapitola i diversi esempi di ricorsione in questo volume e nel successivo "Tecniche avanzate". Alcuni corsi rimandano la trattazione della ricorsione ai capitoli avanzati, mentre noi crediamo che sia preferibile un approccio graduale che inizi già dai primi capitoli del testo. La collezione di esercizi che terminano il capitolo includono diversi esempi classici sulla ricorsione, come la Torre di Hanoi. Capitolo 7 — Gli array. Spiega come elaborare liste e tabelle di dati. Questo capitolo discute la strutturazione dei dati in array, ovvero in gruppi di dati dello stesso tipo correlati, e mostra come gli array facilitano i compiti degli oggetti. Nella prima parte del capitolo utilizziamo gli array in stile C che, come vedremo nel capitolo 8, sono in realtà puntatori a locazioni di memoria consecutive. Arriveremo a vedere gli array come oggetti a tutti gli effetti nell'ultima sezione del capitolo, quando presenteremo il template di classe vector della libreria standard. Il capitolo presenta numerosi esempi di array a una e più dimensioni e varie manipolazioni di array di uso comune, la creazione di istogrammi, l'ordinamento di dati, il passaggio di array a funzioni. Il capitolo include le due versioni finali della classe GradeBook nelle quali si utilizza un array per memorizzare, per l'intera esecuzione del programma, i voti inseriti dall'utente ed evitare inserimenti multipli per diverse elaborazioni. La prima versione utilizza un array monodimensionale per memorizzare i voti e produce un riepilogo finale con voto minimo e massimo, media dei voti e istogramma della distribuzione delle frequenze dei diversi voti. La seconda versione, che è anche quella finale, utilizza un array bidimensionale per memorizzare i voti di un numero di studenti per diversi esami all'interno di uno stesso semestre. La classe produce la media per semestre di ogni studente oltre al minimo e massimo voto complessivo e a un istogramma di distribuzione dei voti. L'ordinamento e la ricerca dei dati sono argomenti fondamentali di questo capitolo. Gli esercizi a fine capitolo includono diversi problemi interessanti e stimolanti, come le tecniche di ordinamento avanzate, la progettazione di un sistema di prenotazione aerea automatizzata, un'introduzione alla "turtle graphics" che deve la fama al linguaggio LOGO, e infine i problemi del "Giro del cavallo" e delle "Otto regine", che introducono il concetto di programmazione euristica, largamente impiegata nel campo dell'intelligenza artificiale. Gli esercizi si concludono con diversi problemi di ricorsione tra cui l'ordinamento per selezione, i palindromi, la ricerca lineare, la ricerca binaria, le "Otto regine", la visualizzazione di un array, la visualizzazione di una stringa al contrario e la ricerca del valore minimo presente in un array. Capitolo 8 — Puntatori e stringhe. Presenta una delle caratteristiche del linguaggio più potenti, i puntatori. Il capitolo fornisce una spiegazione dettagliata degli operatori di manipolazione dei puntatori, della chiamata per riferimento, delle espressioni di puntamento, dell'aritmetica dei puntatori, della relazione tra array e puntatori, degli array di puntatori e dei puntatori a funzioni. Viene mostrato l'uso di const con i puntatori per applicare il principio del minimo privilegio e costruire software più robusto. Viene inoltre presentato l'operatore sizeof per calcolare la dimensione in byte dei tipi di dato durante la compilazione. C'è una stretta correlazione in C++ tra puntatori, array e stringhe, per cui vengono introdotti anche i concetti di base sulla manipolazione delle stringhe e il funzionamento di alcune funzioni di manipolazione molto utilizzate, come getline (input di una linea di testo), strcpy e strncmpy (copia di una stringa), strcat e strncat (concatenamento di due stringhe), strcmp e strncmp (confronto di due stringhe), strtok (estrazione di elementi, o token, da una stringa) e strlen (calcolo della lunghezza di una stringa). Nel libro vengono principalmente utilizzati gli oggetti string del capitolo 3 al posto delle stringhe basate sui puntatori char *. Tuttavia in questo capitolo si utilizzano le stringhe char * per permettere al lettore di padroneggiare l'uso dei puntatori e prepararsi al mondo del lavoro, dove molto codice scritto in C negli ultimi trent'anni utilizza quella rappresentazione delle stringhe. In questo modo si suppone che il lettore familiarizzi con entrambi i modi di rappresentare le stringhe in C++. Molti ritengono che l'argomento dei puntatori sia di gran lunga il più complesso in un corso di programmazione introduttivo. In C e nel C++ non orientato agli oggetti, gli array e le stringhe sono in realtà puntatori a celle di memoria consecutive, e sono puntatori persino i nomi delle funzioni. Lo studio attento di questo capitolo dovrebbe ripagarvi di una comprensione profonda di questo complesso argomento. Il capitolo è ricco di esercizi stimolanti. Questi esercizi includono la classica simulazione della gara di corsa tra la tartaruga e la lepre, gli algoritmi di mescolamento e distribuzione delle carte da gioco, l'ordinamento veloce (quicksort) ricorsivo e l'attraversamento ricorsivo di un labirinto. Abbiamo incluso anche la sezione speciale "Costruite il vostro computer", che introduce la programmazione in linguaggio macchina e guida il lettore nella progettazione e nell'implementazione di un simulatore di computer, che consente di scrivere ed eseguire dei programmi in linguaggio macchina. Questo esercizio alquanto insolito è una caratteristica del nostro corso e sarà di notevole aiuto ai lettori che vogliono comprendere come funziona realmente un computer. Troviamo che i nostri studenti generalmente si appassionano a questo progetto e spesso ne implementano miglioramenti sostanziali, alcuni dei quali sono suggeriti direttamente da noi nella sezione degli esercizi. C'è una seconda sezione speciale che include esercizi di manipolazione di stringhe stimolanti come l'analisi dei testi, il word processing, la visualizzazione di dati in diversi formati, il controllo della protezione, la scrittura dell'equivalente in lettere della somma di un assegno, il codice Morse e la conversione metrica dal sistema metrico decimale a quello anglosassone. Capitolo 9 – Le classi: prima parte. Continua lo studio della programmazione orientata agli oggetti. Il capitolo utilizza la classe Time per illustrare l'accesso ai membri di una classe, la separazione di interfaccia e implementazione, l'utilizzo di funzioni di accesso e di utilità, l'inizializzazione di oggetti tramite costruttori, la loro distruzione tramite distruttori, l'assegnamento di default membro a membro e il riutilizzo del software. Gli studenti possono imparare l'ordine di chiamata dei costruttori e dei distruttori durante il ciclo di vita di un oggetto. Una modifica della classe Time illustra il problema che si genera quando una funzione membro restituisce un riferimento a un dato membro private, rompendo l'incapsulamento di una classe. Gli esercizi a fine capitolo stimolano gli studenti a sviluppare classi per rappresentare orari, date, rettangoli e gioco del tris. Generalmente gli studenti si appassionano ai programmi di gioco. Il lettore più incline alla matematica gradirà gli esercizi sulla classe Complex (numeri complessi), sulla classe Rational (numeri razionali) e sulla classe HugeInteger (numeri interi arbitrariamente grandi). Capitolo 10 – Le classi: seconda parte. Continua lo studio delle classi e presenta nuovi concetti della programmazione orientata agli oggetti. Il capitolo spiega come dichiarare e utilizzare oggetti e funzioni membro costanti, la composizione (che permette di creare nuove classi che contengono come membri oggetti di altre classi), le funzioni e le classi friend che hanno diritti di accesso speciali ai dati private e protected delle classi, il puntatore this che consente a un oggetto di conoscere il proprio indirizzo, l'allocazione dinamica della memoria, i membri static che consentono di memorizzare e manipolare dati comuni a tutti gli oggetti di una classe, e mostra infine alcuni esempi di tipi di dati astratti molto utilizzati (array, stringhe e code), di classi container e di iteratori. Gli esercizi del capitolo chiedono allo studente di sviluppare una classe "conto corrente" e una classe per insiemi di interi. Nella discussione degli oggetti costanti viene fatto brevemente riferimento alla parola chiave mutable, che serve per modificare l'implementazione "invisibile" degli oggetti const. Nel capitolo discutiamo anche l'allocazione dinamica della memoria con new e delete. Se new non riesce ad allocare la memoria richiesta di deafult il programma termina perché new "lancia un'eccezione" nel C++ standard. Abbiamo inserito la spiegazione dei membri static in un esempio di videogioco. In tutto in libro poniamo l'accento sull'importanza di tenere nascosti i dettagli di implementazione ai client di una classe e introduciamo quindi le classi proxy, che rappresentano un meccanismo efficace per nascondere l'implementazione (compresi i dati private) ai client di una classe. Gli esercizi del capitolo includono lo sviluppo di classi per la rappresentazione di un libretto di risparmio e di un insieme di interi. Capitolo 11 – La ridefinizione degli operatori. Presenta uno tra gli argomenti più importanti di un corso di C++ ed è molto apprezzato dagli studenti, perché lo trovano perfettamente conseguente alla discussione dei capitoli 9 e 10. La ridefinizione degli operatori consente di indicare al compilatore come interpretare gli operatori già esistenti quando vengono utilizzati con i nuovi oggetti creati dall'utente. Il C++ sa già come utilizzare questi operatori con gli oggetti dei tipi predefiniti come interi, numeri in virgola mobile e caratteri. Supponiamo dunque di creare una nuova classe di stringhe String: che cosa potrebbe significare il segno più tra due oggetti String? Molti programmatori utilizzano il segno più (+) con le stringhe per indicare il concatenamento. In questo capitolo si spiega come "ridefinire" il segno più in modo tale che quando il compilatore lo rileva in un'espressione tra due oggetti String genera una chiamata alla funzione operatore che effettua il concatenamento. Il capitolo discute i concetti di base della ridefinizione degli operatori, le restrizioni, la ridefinizione con le funzioni membro di una classe e con le funzioni non membro, la ridefinizione di operatori unari e binari e la conversione tra tipi. Una caratteristica del capitolo è costituita dai diversi esempi significativi tra cui una classe di array, una di stringhe, una di date, una di interi di grandi dimensioni e una di numeri complessi (gli ultimi due compaiono negli esercizi insieme con il codice completo). Lo studente più incline alla matematica vorrà cimentarsi negli esercizi con la creazione di una classe di polinomi. Questo materiale è diverso da quello che normalmente si può trovare in corsi simili al nostro. La ridefinizione degli operatori è un argomento complesso ma di notevole valore aggiunto, perché consente di dare una "rifinitura" finale alle proprie classi. Le discussioni sulla classe Array e sulla classe String sono di particolare interesse per gli studenti che hanno intenzione di studiare successivamente le classi della libreria standard string e vector. Gli esercizi incoraggiano lo studente a integrare la ridefinizione degli operatori nelle classi Complex, Rational e HugeInteger, per poter manipolare questi oggetti con dei simboli, come in matematica, piuttosto che con chiamate di funzione, come accadeva negli esercizi del capitolo 10. Capitolo 12 – L'ereditarietà. Introduce una delle funzionalità principali dei linguaggi orientati agli oggetti. L'ereditarietà è una forma di riutilizzo del software grazie alla quale è possibile sviluppare nuove classi in modo facile e rapido, "assorbendo" le funzionalità di altre classi esistenti e aggiungendone di nuove. Nel contesto di una gerarchia di ereditarietà di dipendenti di un'azienda vengono presentati cinque esempi che introducono i dati private e protected e l'ingegneria del software con l'ereditarietà. Viene inizialmente presentata una classe con dati membro private e funzioni membro public per manipolarli. Viene quindi implementata una seconda classe con capacità aggiuntive dove viene intenzionalmente duplicato molto codice. Il terzo esempio inizia lo studio vero e proprio dell'ereditarietà e del riutilizzo del codice: viene usata la classe del primo esempio come classe base dalla quale vengono facilmente ereditati dati e funzionalità in una seconda classe. Questo esempio introduce il meccanismo dell'ereditarietà e mostra che una classe derivata non può accedere direttamente ai dati membro private della classe base. Ciò conduce all'introduzione del quarto esempio che dichiara i dati membro della classe base come protected e mostra che, in tal caso, la classe derivata può accedere direttamente ai dati membro della classe base. L'ultimo esempio utilizza i corretti principi di ingegneria del software dichiarando i dati membro della classe base come private e utilizzando funzioni membro public per accedere ai dati della classe base nella classe derivata. Il capitolo discute i concetti di classe base e classe derivata, membri protected, ereditarietà di tipo public, protected e private, classi base dirette e indirette, costruttori e distruttori di classe base e derivata; infine discute dell'ingegneria del software con l'ereditarietà. Il capitolo confronta l'ereditarietà (relazione "è-un") con la composizione (relazione "ha-un"). Capitolo 13 – Il polimorfismo. Introduce un'altra funzionalità importante della programmazione orientata agli oggetti, il comportamento polimorfo. Quando diverse classi sono correlate per mezzo dell'ereditarietà a una classe base comune, ogni oggetto di una classe derivata può essere trattato come un oggetto della classe base: ciò consente di scrivere programmi generici e indipendenti dai tipi specifici delle classi derivate. Si possono gestire con uno stesso programma nuovi tipi di oggetto, e ciò contribuisce a rendere un sistema estensibile. Il polimorfismo consente di evitare la complessa logica degli switch nei programmi, a favore di una logica lineare più comprensibile. Lo screen manager di un videogioco, per esempio, può inviare semplicemente un messaggio "disegna" a tutti gli elementi di una lista concatenata di oggetti da disegnare sullo schermo: ciascun oggetto saprà come disegnare se stesso. Inoltre si può aggiungere un nuovo oggetto al programma senza modificare quest'ultimo, sempre che il nuovo oggetto sappia come disegnare se stesso. Il capitolo discute di come si implementa un comportamento polimorfo con le funzioni virtuali. Si mostra la distinzione tra classi astratte, da cui non è possibile istanziare oggetti, e classi concrete, da cui ciò è possibile. Le classi astratte sono utili per fornire un'interfaccia ereditabile dalle classi di una gerarchia. Viene inoltre mostrato l'utilizzo delle classi astratte e del polimorfismo con la gerarchia presentata nel capitolo 12: viene introdotta una classe base astratta Employee dalla quale ereditano direttamente le classi CommissionEmployee, HourlyEmployee e SalariedEmployee e indirettamente la classe BasePlusCommissionEmployee. Per soddisfare la curiosità riguardo al consumo aggiuntivo di risorse che il polimorfismo inevitabilmente implica, abbiamo sviluppato una sezione che illustra in dettaglio l'implementazione del polimorfismo in C++ e quindi gli influssi dello stesso sul tempo di esecuzione e sul consumo aggiuntivo di memoria. Viene fornita una descrizione precisa delle vtable (tabelle delle funzioni virtuali) create automaticamente dal compilatore nella gestione del polimorfismo. Per concludere viene introdotta l'informazione sui tipi in fase di esecuzione (Run-Time Type Information - RTTI) e il cast dinamico, che permettono a un programma di determinare in fase di esecuzione il tipo di un oggetto e di agire di conseguenza. Utilizzando RTTI e cast dinamico è possibile accreditare una maggiorazione del 10% a certi tipi di dipendenti e calcolarne le retribuzioni, continuando a calcolare le retribuzioni degli altri tipi di dipendenti in modo polimorfo. | << | < | > | >> |Pagina 22Concetti di baseIniziamo dunque a introdurre un po' di terminologia. Guardatevi intorno: dovunque rivolgiate il vostro sguardo li vedete: oggetti! Persone, animali, piante, automobili, aerei, palazzi, computer e quant'altro. Gli uomini pensano in termini di oggetti. Telefoni, case, semafori, forni a microonde, condizionatori sono altri esempi di oggetti che vediamo ogni giorno intorno a noi. Possiamo suddividere gli oggetti in due grandi categorie: oggetti animati e inanimati. I primi sono vivi, si muovono e intraprendono azioni, al contrario dei secondi. Tuttavia entrambi i tipi di oggetti hanno una caratteristica in comune: gli attributi, come la dimensione, la forma, il colore e il peso. Inoltre hanno tutti dei comportamenti: una palla rotola, rimbalza, si gonfia o si sgonfia; un bambino piange, dorme, gattona, cammina e sbatte le palpebre; un'automobile accelera, frena e svolta; un asciugamano assorbe l'acqua. Noi studieremo i tipi di attributi e i comportamenti che caratterizzano gli oggetti software. Gli esseri umani imparano delle cose sugli oggetti studiando i loro attributi e osservandone i comportamenti. Oggetti diversi possono avere attributi e comportamenti molto simili. Per esempio si può fare un confronto tra i bambini e gli adulti, o tra gli esseri umani e gli scimpanzé. Il progetto di sistemi software orientati agli oggetti (OOD, Object Oriented Design) modella gli oggetti software sulla base degli oggetti del mondo reale. Essa si avvale del concetto di classe, per cui gli oggetti di una determinata classe (per esempio la classe dei veicoli) hanno le stesse caratteristiche (automobili, camion, vagoni e pattini hanno molto in comune). Si avvale poi di relazioni di ereditarietà, secondo le quali nuove classi di oggetti sono derivate da classi esistenti, ereditando le loro caratteristiche ed estendendole con caratteristiche proprie. Ad esempio, un oggetto della classe automobile decappottabile ha le stesse caratteristiche di un oggetto della classe automobile, ma il suo tetto si può aprire e chiudere. La programmazione a oggetti ci dà un modo più naturale e intuitivo di pensare al processo della programmazione, modellando gli oggetti del mondo reale, i loro attributi e i loro comportamenti. La OOD modella anche la comunicazione tra gli oggetti. Essi comunicano tra loro tramite messaggi, proprio come le persone (per esempio come un sergente che mette la truppa sull'Attenti!). Un oggetto conto bancario potrebbe, ad esempio, ricevere un messaggio che impone di ridurre l'ammontare del denaro sul conto in seguito a un prelievo effettuato presso uno sportello. La OOD incapsula i dati (gli attributi) e le funzioni (i comportamenti) in pacchetti detti oggetti: i dati e le funzioni di un oggetto sono intimamente correlati. Gli oggetti hanno anche la proprietà del mascheramento delle informazioni: sebbene gli oggetti possano sapere come comunicare tra loro attraverso interfacce ben definite, non sempre hanno la possibilità di conoscere la struttura interna degli altri oggetti perché i dettagli di implementazione sono nascosti all'interno di ciascun oggetto. È possibile, infatti, guidare un'automobile senza sapere come funziona il motore, la trasmissione e i dettagli degli altri sistemi interni. Vedremo in seguito perché il mascheramento delle informazioni è di importanza cruciale per la creazione di software di buona qualità. I linguaggi come il C++ sono orientati agli oggetti; la programmazione in tali linguaggi si dice programmazione orientata agli oggetti (OOP — Object Oriented Programming) e permette ai programmatori di trasformare un progetto orientato agli oggetti in un sistema funzionante. I linguaggi come il C sono, invece, linguaggi procedurali, e la programmazione tende a essere orientata all'azione. In C l'unità di programmazione è la funzione. In C++ l'unità è la classe, da cui eventualmente si istanziano (creano) gli oggetti. Le classi del C++ contengono funzioni che implementano le operazioni e i dati che implementano gli attributi.
I programmatori C si concentrano sulla scrittura di funzioni, cioè di gruppi
di azioni che effettuano un'operazione completa. Un programma è costituito da un
insieme di funzioni. I dati sono importanti anche in C, naturalmente, ma il
concetto è che essi sono soltanto un supporto alle azioni da intraprendere. I
verbi
presenti nelle specifiche (descrizioni) di un sistema guidano il programmatore C
nel determinare l'insieme di funzioni che devono lavorare insieme per
implementarlo.
Classi, dati e funzioni membro Chi programma in C++, invece, concentra l'attenzione sulla creazione di nuovi tipi di dato, detti classi. Una classe contiene sia i dati che le funzioni deputate a manipolarli, per produrre infine dei servizi ai client (ovvero altre classi o funzioni che utilizzano la classe). I componenti di una classe che sono dati sono detti dati membro. Una classe di conti bancari, ad esempio, potrebbe includere un numero di conto e un saldo dello stesso. Le funzioni di una classe sono dette funzioni membro (o metodi in Java). Una classe di conti bancari potrebbe, ad esempio, prevedere funzioni membro per effettuare un deposito (aumentare il saldo), effettuare un prelievo (diminuire il saldo) e verificare a quanto ammonta il saldo attuale. Il programmatore utilizza i tipi di dato predefiniti (e altri tipi di dato definiti dall'utente) come mattoni per la costruzione dei propri tipi di dato. Con questo approccio i programmatori C++ sono guidati, nel determinare l'insieme delle classi necessarie, dai nomi presenti nelle specifiche di un sistema; dalle classi si creano poi gli oggetti che opereranno in sinergia per implementare il sistema. La relazione fra classi e oggetti può essere riassunta nel modo seguente: i progetti edilizi stanno alle case allo stesso modo in cui le classi stanno agli oggetti. Infatti, è possibile costruire parecchie case partendo dallo stesso progetto e, allo stesso modo, possiamo istanziare parecchi oggetti da una sola classe. Non si può cucinare nella cucina di un progetto o dormire in una camera sulla carta: si può solo cucinare e dormire in una casa vera. Le classi possono inoltre presentare relazioni con altre classi: per esempio, nella concettualizzazione orientata agli oggetti di una banca, la classe "impiegato allo sportello" sarebbe necessariamente in relazione con le classi "cliente", "cassiere", "addetto alla sicurezza" e così via. Tali relazioni prendono il nome di associazioni.
Le classi che costituiscono un sistema software possono essere riutilizzate
in un secondo momento in altri sistemi. Sono in circolazione dei pacchetti di
componenti riutilizzabili che contengono per l'appunto gruppi di classi
correlate. Se ci consentite un paragone, così come gli agenti immobiliari
enfatizzano la parola "locazione" per l'influenza che ha sul prezzo dei
fabbricati, in modo analogo noi enfatizziamo una sola parola per l'influenza che
avrà sul futuro del software: "riutilizzo".
|