|
|
| << | < | > | >> |IndiceIntroduzione XIII PARTE PRIMA UNA RAPIDA PANORAMICA SU VISUAL C++ Capitolo 1 Il compilatore Visual C++, versione 5 3 1.1 Hardware consigliato 5 1.2 Una tipica installazione Windows 7 1.3 Documentazione 8 1.4 Il sistema di sviluppo 9 1.5 Novità 12 1.6 Importanti caratteristiche del compilatore 14 1.7 Opzioni del compilatore 18 Capitolo 2 Utilizzo dell'IDE 23 2.1 Avvio dell'IDE di Visual C++ 24 2.2 Accesso alla guida sensibile al contesto 24 2.3 Informazioni generali sui menu 25 2.4 Barre degli strumenti fisse e mobili 26 2.5 Il menu File 27 2.6 Il menu Edit 31 2.7 Il menu View 36 2.8 Il menu Insert 39 2.9 Il menu Project 40 2.10 Il menu Build 42 2.11 Il menu Tools 45 2.12 Il menu Window 48 2.13 Il menu Help 50 Capitolo 3 Scrittura, compilazione e debugging 53 3.1 Avvio di Developer Studio 54 3.2 Creazione del primo programma 54 3.3 Modifica del codice sorgente 56 3.4 Salvataggio dei file 57 3.5 Creazione del file eseguibile 58 3.6 Debugging dei programmi 62 3.7 Esecuzione del primo programma 70 3.8 Tecniche avanzate di debugging 76 3.9 Premessa al capitolo seguente 78 Capitolo 4 Caratteristiche avanzate di Visual C++ 79 4.1 Creazione di risorse del sistema 80 4.2 Documentazione in linea 83 4.3 Strumenti di diagnostica 87 4.4 Premessa al capitolo seguente 90 PARTE SECONDA FONDAMENTI DI PROGRAMMAZIONE Capitolo 5 Programmazione in C e C++ 93 5.1 Storia del C 93 5.2 American National Standards Institute, ANSI C 100 5.3 Dal C al C++ e alla programmazione orientata agli oggetti 102 5.4 Storia del C++ 103 5.5 Componenti fondamentali di un programma in C/C++ 109 Capitolo 6 Operazioni sui dati 123 6.1 Identificatori 124 6.2 Parole chiave 126 6.3 Tipi di dati standard del C e del C++ 126 6.4 Modificatori di accesso 135 6.5 Modificatori pascal, cdecl, near, far e huge 138 6.6 Conversione di tipi di dati 141 6.7 Classi di memoria 143 6.8 Operatori particolari 148 6.9 Livelli di precedenza degli operatori 158 6.10 Librerie standard C e C++ 159 Capitolo 7 Controllo dei programma 167 7.1 Controlli condizionali 167 7.2 Controlli di ciclo 182 Capitolo 8 Scrittura e utilizzo di funzioni 201 8.1 Prototipo di una funzione 202 8.2 Argomenti delle funzioni 208 8.3 Tipi restituiti dalle funzioni 215 8.4 Argomenti della riga di comando 224 8.5 Funzioni in C e in C++ 228 8.6 Regole da non violare per le funzioni 233 Capitolo 9 Array 239 9.1 Che cosa sono gli array? 239 9.2 Proprietà degli array 240 9.3 Dichiarazioni di array 241 9.4 Inizializzazione di array 242 9.5 Accesso agli elementi dell'array 244 9.6 Calcolo della dimensione degli array 247 9.7 Indici degli array fuori dai limiti 249 9.8 Output e input di stringhe 250 9.9 Array multidimensionali 252 9.10 Array come argomenti di funzioni 256 9.11 Funzioni per stringhe e array di caratteri 264 Capitolo 10 Puntatori 271 10.1 Variabili puntatore 272 10.2 Puntatori a funzioni 296 10.3 Memoria dinamica 300 10.4 Puntatori e array: uno sguardo ravvicinato 305 10.5 Tipo di riferimento del C++ 319 Capitolo 11 Operazioni di I/O in C 323 11.1 Funzioni per la gestione dei flussi di dati 325 11.2 Input e output a basso livello in C 330 11.3 Input e output di caratteri 331 11.4 Input e output di stringhe 333 11.5 Input e output di interi 335 11.6 Formattazione dell'output 338 11.7 Utilizzo di fseek(), ftell() e rewind() 344 11.8 Formattazione dell'input 349 Capitolo 12 Introduzione alle operazioni di I/O in C++ 353 12.1 Operazioni di I/O più semplici con il C++ 353 12.2 Da STREAM.H a IOSTREAM.H 362 Capitolo 13 Strutture, union e altri argomenti 379 13.1 Le strutture 379 13.2 Le union 399 13.3 Argomenti vari 401 Capitolo 14 Programmazione avanzata 407 14.1 Compatibilità fra tipi 408 14.2 Le macro 411 14.3 Istruzioni al preprocessore 416 14.4 La compilazione condizionale 421 14.5 Operatori del preprocessore 422 14.6 Impiego dei file di intestazione 424 14.7 File di intestazione più efficienti 425 14.8 File di intestazione precompilati425 14.9 LIMITS.H e FLOAT.H 427 14.10 Trattamento degli errori: perroro429 14.11 Allocazione dinamica della memoria: le liste collegate 429 14.12 Una semplice lista collegata 432 Capitolo 15 Programmazione avanzata: le librerie 435 15.1 I principali file di intestazione435 15.2 Le funzioni della libreria standard (STDLIB.H) 436 15.3 Le funzioni sui caratteri (CTYPE.H) 444 15.4 Le funzioni sulle stringhe (STRING.H) 450 15.5 Le funzioni matematiche (MATH.H) 458 15.6 Le funzioni relative a tempi e durate (TIME.H) 460 15.7 La parte seguente 466 PARTE TERZA LE BASI DELLA PROGRAMMAZIONE ORIENTATA AGLI OGGETTI Capitolo 16 Programmazione orientata agli oggetti 469 16.1 Niente di nuovo sotto il sole 471 16.2 La programmazione strutturata tradizionale 472 16.3 La programmazione orientata agli oggetti 472 16.4 Il C++ e la programmazione orientata agli oggetti 473 16.5 Terminologia 474 16.6 Un primo sguardo alle classi in C++ 477 Capitolo 17 Le classi in C++ 487 17.1 Caratteristiche speciali delle classi 487 17.2 Overloading di operatori 502 17.3 Classi derivate 506 Capitolo 18 Input e output in C++ 511 18.1 I tipi enumerati in C++ 511 18.2 Variabili riferimento 512 18.3 Argomenti di default 515 18.4 La funzione memset() 516 18.5 Formattazione dell'output 516 18.6 Opzioni di input/output 520 18.7 Le classi di iostream 521 18.8 File binari 533 18.9 Combinazione di codice C e C++ 535 18.10 Manipolatori univoci 537 Capitolo 19 Lavorare in un ambiente orientato agli oggetti 543 19.1 Uno stack orientato agli oggetti 544 19.2 Una lista collegata orientata agli oggetti in C++ 546 19.3 Approfondimenti sulla programmazione orientata agli oggetti 563 PARTE QUARTA FONDAMENTI DELLA PROGRAMMAZIONE PER WINDOWS Capitolo 20 Concetti e strumenti per Windows 95 e NT 567 20.1 Concetti di base di Windows 568 20.2 Concetti e terminologia della programmazione Windows 577 20.3 Gli strumenti di sviluppo per Windows di Visual C++ 591 Capitolo 21 Applicazioni Windows orientate alle procedure 611 21.1 Una struttura per tutte le applicazioni 611 21.2 Make o utilità Project? 626 21.3 Un semplice programma Windows e il suo modello 631 21.4 Uso di SWP.C come modello 639 21.5 Creazione di un programma per grafici a torta 642 21.6 Programmazione visuale tradizionale 657 Capitolo 22 La libreria Microsoft Foundation Ciass 659 22.1 La necessità di una libreria di classi fondamentali 660 22.2 Considerazioni sul progetto di MFC 661 22.3 Le caratteristiche principali della libreria MFC 662 22.4 Tutto comincia da CObject 663 22.5 Le classi più importanti della libreria MFC 666 22.6 Un'applicazione semplificata 668 22.7 Un progetto lineare consente una manutenzione semplificata 676 Capitolo 23 Applicazioni Windows con MFC 677 23.1 Una semplice applicazione con modello 677 23.2 Disegno nell'arca client 682 23.3 Un'applicazione per serie di Fourier 689 23.4 Un diagramma a barre con risorse 705 23.5 Premessa al capitolo seguente 723 PARTE QUINTA AUTOCOMPOSIZIONI Capitolo 24 Autocomposizioni per classi e applicazioni 727 24.1 L'applicazione Graph 728 24.2 Un elaboratore di testi 750 24.3 Premessa al capitolo seguente 766 Capitolo 25 Introduzione a OLE 769 25.1 Caratteristiche e specifiche di OLE 770 25.2 Costruzione di un'applicazione contenitore 775 25.3 Collaudo dell'applicazione contenitore 795 25.4 Premessa al capitolo seguente 797 Capitolo 26 Controlli ActiveX con la libreria MFC 799 26.1 Controlli ActiveX OLE 800 26.2 Contenitori di controlli 805 26.3 Creazione di un controllo con MFC ActiveX ControlWizard 806 26.4 Personalizzazione del controllo ActiveX iniziale 819 26.5 Collaudo del controllo ActiveXTDCtrl 826 26.6 Ulteriori informazioni sui controlli ActiveX 826 PARTE SESTA APPENDICI Appendice A Tabella dei caratteri ASCII estesi 831 Appendice B Interrupt DOS e relativi parametri 837 Appendice C Librerie a collegamento dinamico 857 Indice analitico 869 |
| << | < | > | >> |Pagina 93A cominciare da questo capitolo vengono trattati l'origine, la sintassi e l'utilizzo dei linguaggi C e C++. Uno studio della storia del C è utile perché spiega il successo della filosofia di progetto del linguaggio e aiuta a capire perché il C e il C++ potrebbero essere i linguaggi da scegliere per il futuro. Prima di procedere, occorre avere acquisito familiarità con l'ambiente di sviluppo Microsoft C/C++. A questo punto si dovrebbe aver già installato il pacchetto, averlo configurato secondo le proprie personali esigenze e aver provato l'utilizzo del compilatore e del debugger integrato. 5.1 Storia dei C Per trattare le origini del linguaggio C occorre iniziare a parlare del sistema operativo UNIX, dal momento che sia il sistema sia la maggior parte dei programmi che vengono eseguiti in esso sono scritti in C. Questo tuttavia non significa che il C sia legato a UNIX o a qualsiasi sistema operativo o macchina. L'ambiente di sviluppo UNIX/C ha dato al C la fama di un linguaggio di programmazione di sistemi, perché è utile per scrivere compilatori e sistemi operativi. Il C è anche utile per scrivere la maggior parte dei programmi in molti campi diversi. Il sistema operativo UNIX fu originariamente sviluppato nel 1969 su quello che sarebbe ora considerato un piccolo DEC PDP-7 presso i laboratori Bell a Murray Hill nel New Jersey. UNIX fu scritto interamente nel linguaggio assembler del PDP-7. Questo sistema operativo era stato progettato in modo da facilitare il compito del programmatore, fornendo utili strumenti di sviluppo, pochi comandi e un ambiente relativamente aperto. Subito dopo lo sviluppo di UNIX, Ken Thompson implementò un compilatore per un nuovo linguaggio chiamato B. A questo punto è utile esaminare le origini e la storia del linguaggio B di Ken Thompson, un diretto predecessore del C. Di seguito è riportato un elenco completo di linguaggi da cui deriva il C: LINGUAGGIO ORIGINI/INVENTORE Algol 60 Progettato da un comitato internazionale all'inizio del 1960. CPL Combined Programming Language, sviluppato a Cambridge e all'università di Londra nel 1963. BCPL Basic Combined Programming Language, sviluppato a Cambridge da Martin Richards nel 1967. B Sviluppato da Ken Thompson, Bell Labs, nel 1970. C Sviluppato da Dennis Ritchie, Bell Labs, nel 1972. Poi nel 1973 fu formato il comitato dell'American National Standards Institute (ANSI) con lo scopo di creare l'ANSI C, una standardizzazione del linguaggio C. L'Algol 60 è un linguaggio apparso alcuni anni dopo l'introduzione del FORTRAN. Questo nuovo linguaggio all'epoca era più complesso ed ebbe una grande influenza sul progetto dei futuri linguaggi di programmazione; i suoi autori prestarono molta attenzione alla regolarità della sintassi, alla struttura modulare e ad altre caratteristiche di solito associate ai linguaggi strutturati ad alto livello. Sfortunatamente, l'Algol 60 non si diffuse mai veramente negli Stati Uniti, a parere di molti per l'astrazione e la genericità del linguaggio. Gli inventori del CPL (Combined Programming Language) intendevano riportare i concetti elevati dell'Algol 60 alla realtà dei computer veri. Però, come l'Algol 60, il CPL era difficile da imparare e da implementare e per questo fu anch'esso un fallimento. Attenendosi ancora al meglio offerto dal CPL, i creatori del BCPL (Basic Combined Programming Language) vollero ridurre il CPL alle sue caratteristiche fondamentali. Ken Thompson, quando progettò il linguaggio B per una prima implementazione di UNIX, stava cercando di semplificare ulteriormente il CPL. Egli riuscì a creare un linguaggio molto scarno che si adattava bene a essere utilizzato sull'hardware di cui disponeva. Tuttavia, sia per il BCPL sia per il B si esagerò troppo nell'ottimizzazione, ottenendo così linguaggi limitati, utili solo per trattare alcuni tipi di problemi. Ad esempio, subito dopo che Ken Thompson aveva implementato il linguaggio B, fu presentata una nuova macchina, chiamata PDP-11. UNIX e il compilatore B furono subito trasferiti sulla nuova macchina. Anche se la PDP-11 era una macchina più grande della precedente PDP-7, rimaneva ancora abbastanza piccola rispetto agli standard attuali: aveva soltanto 24 K di memoria, dei quali 16 K erano utilizzati dal sistema, e 512 K di disco fisso. Si pensò di riscrivere UNIX in B, ma il linguaggio B era lento per il suo progetto interpretativo. C'era anche un altro problema: il B era orientato alla parola, ma la PDP-11 era orientata al byte. Per questi motivi, nel 1971 si cominciò a lavorare a un successore del B, chiamato C. La creazione del C fu attribuita a Dennis Ritchie, che ripristinò alcune generalità perse nel BCPL e nel B. Egli realizzò questo attraverso un accorto utilizzo dei tipi di dati, conservando la semplicità e l'accesso diretto all'hardware che erano gli scopi di progetto originari del CPL. Molti linguaggi sviluppati da persone singole (C, Pascal, Lisp e APL) presentano una coesione interna che manca a quelli creati da ampi gruppi di programmatori (Ada, PL/1 e Algol 60) e inoltre riflettono il campo di competenza dell'autore. Dennis Ritchie era noto per il suo lavoro nel software di sistemi: linguaggi dei computer, sistemi operativi e generatori di programmi.
Viste le aree di competenza di Ritchie, è facile capire
perché il linguaggio C venga scelto per la progettazione di
software di sistemi. Il C è un linguaggio relativamente a
basso livello che consente di specificare ogni dettaglio
nella logica di un algoritmo per ottenere la massima
efficienza dal computer. D'altra parte, il C è anche un
linguaggio ad alto livello che può nascondere i dettagli
dell'architettura del computer, aumentando così l'efficienza
nella programmazione.
A questo punto è utile confrontare il C con altri linguaggi di programmazione. Una possibile sequenza di evoluzione dei linguaggi è mostrata nella Figura 5.1: se la si percorre dal basso verso l'alto, si va dal tangibile ed empirico all'inafferrabile e teorico. I punti rappresentano avanzamenti maggiori, con molti passaggi lasciati fuori. I primi antenati dei computer, come il telaio di Jacquard (1805) e il "motore analitico" di Charles Babbage (1834) erano programmati in modo hardware. Forse un giorno le macchine saranno programmate inserendo un trasmettitore neurale in una spina impiantata nel lobo temporale (memoria del linguaggio) o nell'area di Broca (area motrice del linguaggio). I primi linguaggi assembler, che risalgono al periodo in cui nacquero gli elaboratori elettronici, offrivano un modo per lavorare direttamente con un insieme di istruzioni integrate nel computer ed erano abbastanza facili da apprendere. Dal momento che i linguaggi assembler costringono a pensare in termini di hardware, si doveva specificare ogni operazione nei termini della macchina: muovere bit dentro o fuori dai registri, sommarli, spostare il contenuto da un registro all'altro e salvare i risultati nella memoria. Era un lavoro noioso e che generava facilmente errori. I primi linguaggi ad alto livello, come il FORTRAN, furono creati come alternativa ai linguaggi assembler. Questi linguaggi erano più generali e astratti e consentivano di pensare in termini di problemi pratici, piuttosto che in termini di hardware del computer. Sfortunatamente, i creatori dei linguaggi ad alto livello fecero la supposizione sbagliata che tutti i programmatori abituati a lavorare con i dettagli hardware avrebbero preferito lavorare ad alto livello, ed eccitati all'idea di facilitare la programmazione, tralasciarono alcune opzioni necessarie. Il FORTRAN e l'Algol sono troppo astratti per funzionare a livello di sistemi; sono linguaggi orientati ai problemi, adatti per risolvere problemi in ingegneria, nelle scienze o negli affari. I programmatori che volevano scrivere software di sistemi dovevano ancora affidarsi all'assembler della macchina. In reazione a questa situazione, alcuni sviluppatosi di software di sistemi fecero un passo indietro, o verso il basso per quel che riguarda la sequenza informatica, e crearono la categoria dei linguaggi orientati alle macchine. Come si è visto nella genealogia del C, il BCPL e il B si inseriscono in questa classe di strumenti software di livello molto basso.
Questi linguaggi erano ottimi per una particolare
macchina, ma non molto utili per le altre; erano correlati
troppo strettamente a una particolare architettura. Il
linguaggio C è un passo al di sopra rispetto ai linguaggi
orientati alle macchine ma un passo al di sotto dei
linguaggi risolutori di problemi. Il C è abbastanza vicino
al computer da fornire un grande controllo sui dettagli
dell'implementazione di un'applicazione, ma abbastanza
lontano da poter ignorare i dettagli dell'hardware.
Questo è il motivo per cui il C è considerato un linguaggio
allo stesso tempo di alto e di basso livello.
Il codice sorgente di ogni linguaggio di computer ha un
aspetto peculiare. L'APL ha un aspetto da geroglifico, il
linguaggio assembler ha le sue parole mnemoniche incolonnate
e il Pascal una sintassi di facile lettura. Per quel
riguarda il C, molti programmatori che lo studiano per
la prima volta ritengono che la sua sintassi sia oscura e in
genere ne sono spaventati. Il C contiene molto poco delle
strutture di sintassi familiari e simili all'inglese
che si trovano invece in molti altri linguaggi di
programmazione. Invece, il C mostra allo sviluppatone
software operatori dall'aspetto inusuale e una
gran quantità di puntatori. I nuovi programmatori in C
scopriranno subito una molteplicità di caratteristiche del
linguaggio, le cui radici risalgono all'originario
progenitore hardware/software. I paragrafi seguenti
evidenziano i punti forti del linguaggio C.
Nel C vi sono molte meno regole di sintassi che in altri
linguaggi ed è possibile scrivere un compilatore C di
alta qualità che funzioni in soli 256 K di memoria totale.
In realtà il C contiene più operatori e combinazioni di
operatori che parole chiave.
Il linguaggio C originario, sviluppato da Dennis Ritchie, conteneva soltanto 27 parole chiave. Nello standard ANSI C (trattato più avanti nel paragrafo: "American National Standards Institute, ANSI C") sono state aggiunte varie parole riservate. In Microsoft C/C++ è stato ulteriormente ampliato l'insieme di istruzioni e il numero totale di parole chiave è stato portato a più di 70.
Molte delle funzioni che fanno parte di altri linguaggi
di programmazione non sono incluse nel C. Ad esempio, il C
non contiene alcuna funzionalità integrata di input e
output, né alcuna operazione aritmetica (a parte quelle
fondamentali di addizione e sottrazione) o funzioni di
trattamento delle stringhe. Dal momento che qualsiasi
linguaggio senza queste capacità è poco utile, il C fornisce
un ricco insieme di funzioni di libreria per l'input/output,
le operazioni aritmetiche e la manipolazione delle stringhe.
Questo insieme convenzionale di librerie è utilizzato con
tale frequenza e normalità che può quasi essere considerato
come parte del linguaggio stesso. Uno dei punti di forza del
C è comunque la sua struttura libera, che consente di
ricodificare facilmente queste funzioni.
| << | < | > | >> |Pagina 99Svantaggi del CNon esistono linguaggi di programmazione perfetti: problemi di programmazione differenti richiedono soluzioni diverse. E' compito dell'ingegneria del software scegliere il linguaggio migliore per un progetto. Questa è una delle prime decisioni da prendere ed è quasi irrevocabile una volta iniziata la stesura del codice. La scelta del linguaggio di programmazione può anche essere l'elemento determinante per il successo o il fallimento di un progetto. I paragrafi seguenti trattano alcuni punti deboli del linguaggio C per chiarire meglio quando conviene utilizzare il C per una particolare applicazione e quando no. Controllo dei tipi molto limitato Il fatto che il C sia un linguaggio non fortemente tipizzato è uno dei suoi punti di forza, ma anche una sua debolezza. Tecnicamente, la tipizzazione è una misura di quanto strettamente un linguaggio faccia rispettare l'utilizzo dei tipi di variabile (ad esempio, i numeri interi e quelli in virgola mobile sono due tipi differenti). In alcuni linguaggi è illegale assegnare un tipo di dati a un altro senza richiamare una funzione di conversione. Questo evita che i dati vengano compromessi da un arrotondamento inaspettato. Come si è detto in precedenza, il C consente che un intero sia assegnato a una variabile di tipo carattere e viceversa. Ciò significa che è necessario gestire appropriatamente le variabili; per i programmatori esperti questo non è un problema, ma i principianti dovrebbero ricordare che questo può essere fonte di effetti collaterali, ad esempio cambiamenti inattesi nel valore di una variabile o in un altro elemento.
Dal momento che il C non è un linguaggio fortemente
tipizzato, offre una grande flessibilità nel manipolare i
dati. Ad esempio, l'operatore di assegnamento (=) può essere
presente più di una volta nella stessa espressione. Questa
flessibilità, che può essere sfruttata a proprio vantaggio,
comporta anche che possano essere scritte espressioni che
non hanno un valore chiaro e definito. Se si fosse ristretto
l'utilizzo di operatori di assegnamento e simili, eliminando
gli effetti collaterali e i risultati imprevedibili, si
sarebbero ridotti di molto la potenza e l'interesse per il C
come linguaggio assembler ad alto livello.
L'enorme serie di caratteristiche del C, dalla manipolazione dei bit all'I/O formattato ad alto livello, e la sua relativa coerenza da macchina a macchina, lo hanno portato a essere accettato in applicazioni scientifiche, di ingegneria e di affari. Il C ha contribuito direttamente all'ampia disponibilità del sistema operativo UNIX su computer di tutti i tipi e dimensioni. Come ogni altro strumento potente, però, il C impone una forte responsabilità ai sui utenti. I programmatori in C devono acquisire molto velocemente una disciplina, adottando varie regole e convenzioni in modo da rendere i propri programmi comprensibili a se stessi, anche dopo molto tempo, e agli altri, che cercano di analizzare il codice per la prima volta. Nel C è essenziale una disciplina di programmazione, anche se per fortuna questa viene quasi automaticamente con la pratica. | << | < | > | >> |Pagina 1025.3 Dal C al C++ e alla programmazione orientata agli oggettiPer dirla in breve, il C++ è un ampliamento del linguaggio C, di cui conserva tutti i punti di forza del C, compresi la potenza e flessibilità nell'occuparsi dell'interfaccia hardware/software, la programmazione di sistemi a basso livello, l'efficienza, l'economia e le potenti espressioni. Però, il C++ porta il linguaggio C nel mondo dinamico della programmazione orientata agli oggetti e lo rende una piattaforma per l'astrazione ad alto livello dei problemi, superando in questo persino l'Ada. Il C++ realizza tutto questo con una semplicità e un supporto per la modularità simile a quello del Modula-2, mentre conserva la compattezza e l'efficienza di esecuzione del C.
Questo nuovo linguaggio ibrido unisce i costruiti
standard dei linguaggi procedurali, familiari a molti
programmatori, al modello orientato agli oggetti, che è
possibile sfruttare appieno per produrre una soluzione a un
problema orientata agli oggetti. In pratica, un'applicazione
in C++ può riflettere questa dualità incorporando sia il
modello di programmazione procedurale sia il nuovo modello
orientato agli oggetti. Questa duplice forma rappresenta una
speciale sfida per i programmatori che iniziano lo studio
del C++: non vi è da imparare soltanto un nuovo linguaggio,
ma anche un nuovo modo di pensare e risolvere i problemi.
Non sorprende il fatto che il C++ abbia un'origine simile a quella del C. Il C++ è in qualche modo simile al BCPL e all'Algol 68, contiene anche componenti del Simula 67. La capacità del C++ di effettuare l'overloading degli operatori e la flessibilità di includere dichiarazioni vicino al loro primo punto di applicazione sono caratteristiche dell'Algol 68. Il concetto di sottoclassi (o classi derivate) e di funzioni virtuali deriva dal Simula 67. Come molti altri comuni linguaggi di programmazione, il C++ rappresenta un'evoluzione e ridefinizione di alcune delle migliori caratteristiche dei linguaggi precedenti. Naturalmente, quello a cui è più vicino è il C. Lo sviluppo del linguaggio C++ agli inizi degli anni Ottanta è attribuito a Bjarne Stroustrup, di Bell Labs (egli attribuisce l'assegnazione del nome di questo nuovo linguaggio a Rick Mascitti). Il C++ originariamente fu sviluppato per risolvere alcune simulazioni casuali molto precise, per le quali considerazioni di efficienza impedivano l'utilizzo di altri linguaggi. Il linguaggio fu utilizzato per la prima volta al di fuori del gruppo del dott. Stroustrup nel 1983 e nell'estate del 1987 era ancora soggetto a un naturale perfezionamento ed evoluzione. L'obiettivo principale del progetto del C++ era quello di conservare la compatibilità con il C. Lo scopo era quello di salvaguardare l'integrità di milioni di righe di codice C scritto e corretto in precedenza, l'integrità di molte librerie C esistenti e l'utilità di molti strumenti C già sviluppati. Grazie all'alto grado di successo ottenuto nel raggiungere questo obiettivo, molti programmatori trovano la transizione al C++ molto più semplice del passaggio al C da altri linguaggi, come il FORTRAN. | << | < | > | >> |Pagina 469Prima di affrontare l'argomento di questo capitolo, occorre chiarire un punto: l'esecuzione di programmi orientati agli oggetti esige un computer particolare, con uno specifico microprocessore? La risposta è no. In termini di tipi di file, ciò significa che, se un file è eseguibile, non importa la sua provenienza. In altre parole, non importa se il codice sorgente è stato interpretato (come per i programmi in BASIC), compilato (come per i linguaggi assembly, Pascal, FORTRAN, C e C++) oppure compilato e interpretato (come per Java): dopo che il "traduttore" ha generato il formato finale, eseguibile, qualsiasi programma funziona sullo stesso microprocessore. Si tratta ovviamente di un notevole vantaggio: quale che sia la sintassi del codice sorgente, le istruzioni sono infine tradotte in semplici operazioni di somma, sottrazione, confronto, salto e così via, specifiche del microprocessore. Chi conosce un linguaggio assembly, sa quanto sia simile al linguaggio macchina. I linguaggi ad alto livello richiedono all'interprete o al compilatore uno sforzo maggiore per tradurre le istruzioni in una forma comprensibile al computer. Lo sforzo è ancora maggiore per i linguaggi orientati agli oggetti. Il nodo della questione è dunque il traduttore. Vale la pena di sottolineare un fatto: se i linguaggi orientati agli oggetti non richiedono computer di tipo speciale, il motivo è che essi non danno, in termini di capacità esecutive, niente di più di un linguaggio assembly. Quali sarebbero allora i vantaggi di un linguaggio orientato agli oggetti, come il C++? La parola chiave in questo caso è "packaging", ovvero "confezionamento". Per chiarire le cose, è utile un esempio. Si pensi a un programma nel quale siano dichiarate cento variabili di tipo int. La gestione di tante variabili può risultare disagevole; per fortuna esistono gli array: uno strumento logico e sintattico che rende più elegante il codice. Eppure, gli array non aggiungono nulla alle capacità di elaborazione; essi permettono semplicemente di scrivere codice più semplice e chiaro alla lettura. La programmazione orientata agli oggetti non fa che portare molto più avanti questa idea. I linguaggi di programmazione orientati agli oggetti "confezionano" costrutti ben noti al programmatore in costrutti a livello più alto. Le caratteristiche di orientamento agli oggetti del C++ si fondano su basi, in parte derivate dal C, che lo distinguono dagli altri linguaggi. Fra queste basi, alcune, come il modificatore static del C, non sono di per sé orientate agli oggetti, ma si possono utilizzare anche nel nuovo contesto. Il problema di chi si accosta per la prima volta alla progettazione e stesura di codice orientato agli oggetti non è l'apprendere come confezionare i concetti noti, ad esempio come scrivere le funzioni (che nel gergo della programmazione orientata agli oggetti sono dette anche metodi), ma come integrare l'idea del confezionamento con i nuovi costruiti del C++. Vi è un altro aspetto fondamentale da chiarire: non è necessario adottare un linguaggio orientato agli oggetti per scrivere applicazioni per Windows, e si può adottare un linguaggio orientato agli oggetti per scrivere applicazioni per DOS. Occorre cioè distinguere la sintassi dal supporto necessario all'esecuzione di un programma in un sistema operativo multitasking come Windows o in uno più antiquato come il DOS. Spesso i programmatori principianti tendono a confondere le due cose. La confusione è accresciuta dalle forme particolari che il "confezionamento" assume in prodotti commerciali, soprattutto nelle applicazioni per Windows di Microsoft e Borland. Utilizzare tutti gli oggetti a disposizione per la creazione di applicazioni per Windows è un'esperienza a tutta prima impossibile. Per facilitare l'impresa, i produttori, come Microsoft, hanno preselezionato una famiglia di oggetti standard per Windows. Questa "confezione di secondo livello" è stata denominata MFC (Microsoft Foundation Class Library) da Microsoft e OWL (Object Windows Library) da Borland. Ovviamente, mentre le confezioni di primo livello su cui esse si basano sono compatibili fra loro, MFC e OWL non lo sono, perciò il programmatore deve tenere presente che la scelta di uno dei due prodotti chiude la porta all'altro. Per il momento, il mercato è dominato da MFC.
Tanto andava detto a titolo di introduzione. Nel resto
del capitolo si vedrà come i costruiti orientati agli
oggetti si fondano su ciò che il lettore ha già appreso in
precedenza. In particolare, si introdurrà la terminologia
specifica della programmazione orientata agli oggetti, che
spesso non è altro che una ridenominazione dei concetti
della programmazione tradizionale. Ad esempio, si vedrà
che le classi del C++ (un concetto tipico del mondo a
oggetti) sono un'evoluzione delle strutture del C
(un concetto tradizionale).
I pubblicitari sanno bene che un prodotto avrà più successo se la parola "nuovo" compare sulla confezione. Se si applicasse alla programmazione il detto "Niente di nuovo sotto il sole", allora si dovrebbe concludere che la programmazione orientata agli oggetti non è affatto una novità. Scott Guthery afferma: "La programmazione orientata agli oggetti esiste fin dall'invenzione delle subroutine, negli anni Quaranta" ("Are the Emperor's New Clothes Object Oriented?", Dr. Dobb's Journal, dicembre 1989). Nello stesso articolo si sostiene che gli oggetti, pietra angolare della programmazione orientata agli oggetti, esistevano già in linguaggi anteriori, come FORTRAN II. Ciò considerato, per quale motivo solo ora, nell'ultimo decennio del ventesimo secolo, si parla tanto di programmazione orientata agli oggetti? Perché essa è salutata come una grande novità? Probabilmente, la risposta è che i concetti propri di questa tecnica erano già noti negli anni Quaranta, ma non si disponeva del supporto logico-sintattico necessario. I programmatori cresciuti con il BASIC scrivevano lunghissimi programmi senza sfruttare i concetti della programmazione strutturata: pagine e pagine di codice disseminate di variabili globali dal nome oscuro e di istruzioni goto. Leggere, capire e vagliare il codice poteva rivelarsi un incubo. Modificare il codice per arricchirne la funzionalità significava aprire il vaso di Pandora; la manutenzione del codice era quantomeno ardua. Negli anni Sessanta vennero introdotte le idee della programmazione strutturata: nomi significativi per le variabili, variabili locali e lo sviluppo dei programmi per raffinamenti successivi. L'applicazione di queste idee rese più facile leggere, capire e correggere il codice. La manutenzione fu notevolmente semplificata, grazie alla possibilità di intervenire su singole procedure. Nuovi linguaggi di programmazione, come Ada, C e Pascal, incoraggiarono un approccio strutturato ai problemi della programmazione. Bjarne Stroustrup è considerato il padre del C++; egli sviluppò il linguaggio nei primi anni Ottanta, ai laboratori Bell. Lo si può senz'altro considerare il padre della programmazione orientata agli oggetti per come essa si realizza in C++. Secondo Jeff Duntemann, "la programmazione orientata agli oggetti è la Programmazione Strutturata strutturata, la derivata seconda dello sviluppo di software, la Grande Teoria Unificante della struttura dei programmi" ("Dodging Steamships", Dr. Dobb's Journal, luglio 1989). Nel prosieguo si vedrà che le caratteristiche orientate agli oggetti del C++ poggiano sulle caratteristiche del C. Sebbene il C++ sia stato pensato per la programmazione orientata agli oggetti, esso permette di scrivere codice non strutturato od orientato alle procedure. La scelta spetta al programmatore.
Se si considerano i "concetti di programmazione",
l'affermazione di Scott Guthery secondo la quale non c'è in
realtà nulla di nuovo è vera; tuttavia, in questo capitolo
si presenta un elegante metodo di confezionamento per la
programmazione. I linguaggi come il C++ offrono gli
strumenti per entrare nel mondo della programmazione
orientata agli oggetti.
Nei primi capitoli del libro si sono trattate le tecniche tradizionali di programmazione strutturata, orientata alle procedure, in C e C++. La sintassi dei due linguaggi è stata presentata in un contesto tradizionale (chi aveva già esperienza di programmazione con un linguaggio come Pascal, probabilmente ha già applicato quelle tecniche; l'approccio procedurale è comune a tutti i linguaggi strutturati, fra i quali C, C++, Pascal e PL/1). E' stata introdotta la tipica struttura di un programma procedurale, con una funzione principale (main) e un insieme di funzioni accessorie, richiamate da quella. Nei programmi sviluppati in modo top-down, la funzione main è in genere breve; il grosso delle operazioni è delegato alle funzioni accessorie. Il flusso esecutivo parte dall'inizio della funzione principale e prosegue fino alla sua fine.
In questa soluzione, il codice e i dati sono separati.
Le procedure definiscono le trasformazioni subite dai dati,
ma i due elementi non si confondono. Le cose cambiano nella
programmazione orientata agli oggetti. Di fatto, la
soluzione procedurale ha alcuni svantaggi, primo fra tutti
la difficoltà di manutenzione. Ogni modifica al codice
investe l'intero programma; sviluppo e debugging richiedono
perciò molto tempo: è naturale cercare una soluzione più
efficace.
I programmi orientati agli oggetti funzionano diversamente da quelli procedurali. Essi esigono una strategia di programmazione specifica, spesso difficile da cogliere per chi è abituato alle tecniche tradizionali. In questo e nei prossimi tre capitoli si presentano gli elementi della programmazione orientata agli oggetti in C++. Chi ha scritto o esaminato programmi per Windows 3.x, Windows 95 o Windows NT ha già potuto osservare uno dei concetti alla base della programmazione orientata agli oggetti: un programma si compone di un gruppo di oggetti che interagiscono. In C++ gli oggetti si formano mediante un nuovo tipo di dati: class (classe). Una classe è formata da un insieme di valori (dati) e da operazioni (metodi o funzioni membro) che operano sui dati. Le interazioni fra oggetti sono mediate da messaggi. I messaggi sono un elemento comune anche ai programmi per Windows e Presentation Manager. Nella programmazione orientata agli oggetti, gli oggetti comprendono non solo i dati, ma anche i metodi (o funzioni) che operano su di essi. I due elementi sono combinati in un concetto unitario. La programmazione orientata agli oggetti offre al programmatore tre vantaggi. Il primo concerne la manutenzione del codice: i programmi sono più semplici da leggere e da capire; la complessità del programma è controllata in modo che il programmatore veda solo i dettagli necessari. Il secondo vantaggio concerne le modifiche al codice: spesso, per aggiungere funzionalità a un programma, è sufficiente inserire nuovi oggetti. Un nuovo oggetto eredita le caratteristiche di un oggetto genitore e il programmatore deve solo specificare le sue caratteristiche nuove. Il terzo vantaggio è la possibilità di riutilizzare un oggetto. Una volta realizzato e collaudato, un oggetto diventa un elemento che si può inserire in nuovi programmi, senza dover alterare il codice, se non in misura minima.
Nei primi capitoli si è visto come convertire programmi
scritti in C in programmi in C++, operando poche modifiche.
Ad esempio, le chiamate di printf si trasformano in
istruzioni cout. La conversione è semplice perché conserva
la natura procedurale del programma. La programmazione
orientata agli oggetti non è possibile in C per la mancanza
dell'elemento cruciale: le classi. Perciò è più difficile
trasformare un programma procedurale in un programma
orientato agli oggetti: si deve riscrivere radicalmente il
codice, introducendo gli oggetti opportuni. Talvolta
conviene riprogettare il programma da capo, il che può
essere uno svantaggio.
I concetti della programmazione orientata agli oggetti attraversano i confini fra linguaggi. Microsoft Quick Pascal, ad esempio, è stato uno dei primi linguaggi a introdurre gli "oggetti". Che cosa rende il C++ adatto alla programmazione orientata agli oggetti? La risposta, come già si è accennato, è il tipo di dati class. Proprio questo, costruito sul tipo struct del C, permette di creare oggetti. Ma il C++ presenta altre caratteristiche orientate agli oggetti, assenti in altri linguaggi che si limitano a introdurre gli oggetti. Fra tali caratteristiche vanno citate la tipizzazione forte, l'overloading degli operatori e la minore enfasi sul preprocessore. E' vero che si possono scrivere programmi orientati agli oggetti in altri linguaggi, ma i vantaggi del C++ sono rilevanti. Questo linguaggio è stato espressamente progettato, e non semplicemente adattato, per la programmazione orientata agli oggetti. | << | < | > | >> |Pagina 543Anche se il C++ è forse il linguaggio di programmazione orientato agli oggetti più diffuso, ne esistono altri. Ogni linguaggio orientato agli oggetti condivide con gli altri molteplici caratteristiche comuni. Nel libro Object-Oriented Software Construction (Prentice Hall), Bertrand Meyer suggerisce che esistono sette caratteristiclie comuni a tutti i linguaggi orientati agli oggetti: - la modularità basata sugli oggetti; - i tipi di dati astratti; - la gestione automatica della memoria; - le classi; - l'ereditarietà; - il polimorfismo; - l'ereditarietà transitiva (o multipla). Nello studio delle classi del C++ svolto nel Capitolo 17, si è cercato di evidenziare le modalità attraverso cui il Visual C++ fornisce tali caratteristiche. Per programmare davvero in maniera orientata agli oggetti è necessario lavorare con un linguaggio che sia orientato agli oggetti, come ad esempio il C++, a parte valide eccezioni che verranno descritte nel seguito di questo capitolo. Ad esempio, i programmi scritti per Windows offrono molte delle caratteristiche precedenti, sebbene la maggior parte di essi possa essere scritta in C. | << | < | > | >> |Pagina 66022.1 La necessità di una libreria di classi fondamentaliLa libreria MFC fornisce alcuni oggetti molto semplici da utilizzare. Già dal suo concepimento, e sebbene sia stato implementato con un linguaggio tradizionale come il C classico, Windows ha sempre seguito i principi della programmazione orientata agli oggetti. Queste caratteristiche sono state discusse approfonditamente nei due capitoli precedenti. Il matrimonio tra C++ e Windows è stato una conseguenza naturale. Il gruppo di programmatori che ha sviluppato MFC ne ha fatto una esaustiva implementazione dell'interfaccia comune per programmi applicativi visuali (la cosiddetta Application Program Interface, o API di Windows). Questa libreria C++ incorpora le strutture dati e le chiamate API più importanti all'interno di classi riutilizzabili. Le librerie di classi come MFC offrono molti vantaggi rispetto alle librerie di funzioni del C discusse nei capitoli precedenti. Di seguito sono descritti alcuni dei vantaggi apportati dall'uso delle classi C++. - Incapsulamento di codice e dati all'interno di una stessa classe. - Ereditarietà. - Eliminazione delle collisioni tra nomi di variabili e funzioni. - Le classi risultanti appaiono sotto forma di estensioni naturali del linguaggio.
- Il codice risultante dall'uso di librerie
ottimizzate ha dimensioni notevolmente inferiori.
|