Copertina
Autore Chris H. Pappas
CoautoreWilliam H. Murray III
Titolo La guida completa Visual C++ 5
EdizioneMcGraw-Hill, Milano, 1998 , Isbn 978-88-386-0467-6
OriginaleVisual C++ 5: The Complete Reference [1997]
LettoreRenato di Stefano, 1988
Classe informatica: linguaggi
PrimaPagina


al sito dell'editore


per l'acquisto su IBS.IT

per l'acquisto su BOL.IT

per l'acquisto su AMAZON.IT

 

| << |  <  |  >  | >> |

Indice


Introduzione                          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 93

Capitolo 5
Programmazione in C e C++


A 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.

Il C e i linguaggi ad alto livello precedenti

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.

Simbiosi con i tracciati neurali dei cyborg
-
Intelligenza artificiale
Linguaggi di comandi del sistema operativo
Linguaggi orientati ai problemi
Linguaggi orientati alla macchina
Linguaggio assembler
-
Hardware effettivo
- - -
Figura 5.1
Evoluzione teorica
dei linguaggi di programmazione.

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.

Vantaggi dei C

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.
Dimensione dei codice ottimale

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.
Insieme conciso di 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 99

Svantaggi del C

Non 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.
Il C non è adatto a tutti

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 102

5.3 Dal C al C++ e alla programmazione orientata agli oggetti

Per 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.

5.4 Storia dei C++

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 469

Capitolo 16
Programmazione orientata agli oggetti


Prima 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).

16.1 Niente di nuovo sotto il sole

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.

16.2 La programmazione strutturata tradizionale

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.

16.3 La programmazione orientata agli oggetti

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.

16.4 Il C++ e la programmazione orientata agli oggetti

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 543

Capitolo 19
Lavorare in un ambiente
orientato agli oggetti


Anche 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 660

22.1 La necessità di una libreria di classi fondamentali

La 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.

| << |  <  |