C++

- Microsoft Visual C++

- Borland C++ 5.5

- Il Linguaggio C++

    - Tipi di dato

    - Variabili

    - Strutture

    - Espressioni

    - Flusso del programma

    - Funzioni

    - Puntatori

    - Array e tipi enumerativi

- AppWizard: generazione di applicazioni

- ClassWizard e WizardBar: modifica di applicazioni


Microsoft Visual C++

Visual C++ permette di preparare sia applicazioni basate su interfaccia testuale (DOS), sia applicazioni basate su Interfaccia Grafica (Windows), con utilizzo delle classi MFC (Microsoft Foundation Classes).

- Le classi MFC offrono oggetti di alto livello che permettono di produrre applicazioni basate su Interfaccia Grafica.

- Gli Wizard (AppWizard e ClassWizard) aiutano a creare e modificare applicazioni Windows che utilizzano le classi MFC.

- E' possibile programmare direttamente in MFC, senza utilizzare gli Wizard, ma è molto scomodo; conviene comunque provarci per capire meglio come stanno le cose...


Borland C++ 5.5

Il compilatore Borland C++ 5.5 permette di preparare sia applicazioni basate su interfaccia testuale (DOS), sia applicazioni grafiche basate su SDK (Windows), utilizzando cioè le API Win32, anziché MFC.

Il compilatore Borland C++ 5.5 è gratuito8-))) e può essere scaricato dal sito Borland, o da uno dei CD allegati alle riviste di programmazione Windows (p.e. 'DEV' di aprile 2000)

Anche per Borland esiste l'ambiente di sviluppo grafico completo, ma qui non viene trattato. Visitare al riguardo il sito Borland.


Il linguaggio C++

Gli esempi che seguono non prevedono l'interfaccia grafica, e sono compilabili sia con Microsoft Visual C++ che con Borland C++

Gli stessi prodotti sono in grado di compilare sorgenti C

Esempio


 
  • Regole relative alle funzioni:

  • - le istruzioni terminano con ;
    - le righe del programma devono essere fra {}
    - i parametri di funzione devono essere fra ()
     

  • Comunicazione con l'esterno

  • - includere <iostream.h>

    cout <<"Quanti euro?\n";
    cin>>euro;

    cout <<"Quanti euro?" << endl;
    cin>>euro;


    Tipi di dato
     

  • Tipi di dati elementari

  • char
    float
    double
    int
     

  • Tipi meno usati

  • long
    short
    signed
    unsigned
    void
     

  • Costanti

  • const int cambio = 1936.27;

    (meglio #define?)

    Variabili
     

  • Scelta dei nomi

  • Notazione ungherese in ambiente Windows:

    - i puntatori iniziano con p -
    - i puntatori far iniziano con lp
    - le funzioni iniziano con fn
    - gli handle iniziano con h

    Io uso:

    - pt_ per i puntatori
    - fn_ per le funzioni
    - st_ per le strutture

    Strutture
     

  • Dichiarazione

  • class Listino
    {
    public:
    int codice;
    int prezzo;
    };
     

  • Assegnazione del tipo "Listino" a una variabile:

  • Listino st_Ricambi;
     

  • Accesso alle variabili in una struttura

  • st_Ricambi.codice = 5;
     

  • Strutture nidificate

  • class Listino
    {
    public:
    int codice;
    int prezzo;
    };

    class Negozio
    {
    float OraDiApertura, OraDiChiusura;
    int NumeroDiSedie;
    Listino st_Ricambi;
    };
     

  • Nota

  • La parola class si usa anche per definire le classi, che sono strutture contenenti (anche?) funzioni.

    Le strutture si possono definire anche usando la parola struct come nel linguaggio C (non richiede public).

    Espressioni
     

  • Operatori di base

  • * / + - %
     

  • Altri operatori

  • ++ -- >> <<
     

  • Operatori booleani

  • > >= < <= == != ! && ||
     

  • Operatori sui bit

  • - << >> & | ^
     

  • Operatori abbreviati

  • += -= *= /= %= <<= >>= &= |= ^=
     

  • L'operatore ternario ?:

  • espressione-condizionale ? espressione1 : espressione2
     

  • Priorità degli operatori

  • () massima precedenza
    ++ -- ~ !
    * / %
    + -
    >> <<
    < <= > >=
    == !=
    &
    ^
    |
    &&
    ||
    ?: minima precedenza

    (per sicurezza usare le parentesi)


    Flusso del programma

  • if

  • if (espressione)
    istruzione1;
    else
    istruzione2;
     

  • switch

  • switch (espressione)
    {
    case valore1:
    istruzione1;
    break;

    case valore2:
    istruzione2;
    break;

    ...
    default:
    istruzioneDefault;
    }
     

  • ciclo for

  • for (espr-iniz; condizione di permanenza; espr-post)
    istruzione;
     

  • ciclo while

  • while (espressione)
    istruzione;
     

  • ciclo do

  • do
    istruzione;
    while (espressione);

    Funzioni

    void fn_funzione(tipo1 arg1, tipo2 arg2, ...)
    {
    ......
    return espressione;
    }

  • Gestione inline

  • Se una piccola funzione è richiamata con grande frequenza (p.e. in un ciclo, conviene usare la 'gestione inline' per memorizzarla.

    Quando viene richiamata una funzione,

    - vengono salvati i registri della CPU

    - viene creato uno stack per gli argomenti e le variabili locali

    - gli argomenti vengono copiati nello stack

    - viene caricata la funzione nella cache delle istruzioni

    - la funzione viene esguita

    - viene ripulito lo stack

    - vengono ripristinati i registri della CPU

    - viene ricaricata nella cache delle istruzioni la funzione chiamante

    - il controllo viene passato alla funzione chiamante

    Con la 'gestione inline', la funzione viene 'esplosa' nel punto in cui viene richiamata, il che evita tutto il sovraccarico dovuto ai salvataggi/ripristini, che per funzioni piccole possono richiedere più tempo della stessa funzione:

    inline int Fattoriale(int n)...
     

  • Ricorsione

  • Una funzione che richiama sè stessa, ad esempio per eseguire la stessa operazione su un sottoinsieme di elementi, si definisce ricorsiva.
    Le funzioni ricorsive non sono molto usate nella realtà.
     

  • Parametri variabili

  • Per indicare che una funzione può rucevere un numero variabile di parametri (tipo printf) su usano i tre punti (...), p.e.

    int fattoriale(...)

    {

    }

    Puntatori

    Mentre una variabile punta sempre alla stessa area di memoria, l'indirizzo contenuto in un puntatore può essere modificato.
    Un puntatore può puntare ad un'area di memoria dinamica, senza nome.

    Un puntatore ad un'area di un certo tipo viene dichiarato come si dichiara una variabile di quel tipo, col nome preceduto da *; p.e.:

    int *pt_prova;

    dichiarare un puntatore ad un intero.

    Il carattere * si utilizza anche per 'deindirizzare' il puntatore, cioè per fare riferimento al valore puntato:

    a = *pt_prova;

    assegna alla variabile 'a' il valore presente nell'area a cui punta 'pt_prova'.

    *pt_prova = 5;

    memorizza il valore 5 nell'area a cui punta 'pt_prova' (può essere, p.e., una variabile oppure l'elemento di un array)

    Per assegnare 'direttamente' ad un puntatore l'indirizzo di una variabile, si usa '&':

    pt_prova = &var;

    carica nel puntatore 'pt_prova' l'indirizzo della variabile 'var'.

    Per caricare in un puntatore l'indirizzo di un'area dinamica appena creata, si usa new:

    int *pt_intero;
    pt_intero = new int;

    idem per una nuova struttura:

    Listino *pt_st_Ricambi;
    pt_st_Ricambi = new Listino;

    Per liberare la memoria occupata da un oggetto allocato dinamicamente, si fa il delete del puntatore a quell'oggetto:

    delete pt_intero;
    pt_intero = 0; // per sicurezza
     

  • Esempio

  • #include <iostream.h>
    void main()
    {
    int numero, *pt_num;
    pt_num = &numero;
    cout << "Immetti un numero: ";
    cin >> numero;
    cout << "Hai immesso " << *pt_num << " cioè " << numero << endl;
    cout << "Il valore è memorizzato all'indirizzo hex " << pt_num;
    }
     

  • Strutture

  • Se pt_struttura punta a una struttura, per indirizzarne un elemento si può utilizzare la forma

    (*pt_struttura).elemento (come se fosse st_nome_struttura.elemento)

    oppure la notazione semplificata

    pt_struttura->elemento
     

  • Stringhe

  • Una stringa è una serie di caratteri il cui ultimo carattere è '\0'.

    Il nome di una stringa è un puntatore al primo carattere della stringa.

    La maggior parte delle funzioni di libreria che agiscono sulle stringhe inizia con i caratteri 'str' (strcpy, strlen, strcat, ecc.).

    Il linguaggio C++ include un oggetto chiamato 'classe per stringhe ANSI' utile per creare e manipolare le stringhe.
     

  • Argomeni indirizzo

  • Invece di far lavorare le funzioni su variabili globali, conviene passare degli argomenti, che la funzione non potrà modificare.

    E' possibile passare ad una funzione non diretttamente un argomento, ma un puntatore ad un argomento. In questo caso la funzione chiamata può modificare direttamente la variabile nella funzione chiamante:
     

  • Esempio - versione C

  • /* sfera.c */
    #include <stdio.h>
    #define PI_GRECO 3.14159
    int main()
    {
    int calcola(float raggio, float *pt_area, float *pt_volume);
    float raggio;
    float area;
    float volume;
    printf("Digita il valore del raggio: ");
    scanf("%f",&raggio);
    calcola(raggio, &area, &volume);
    printf("Area della sfera di raggio %f: %f\n",raggio, area);
    printf("Volume della sfera di raggio %f: %f\n",raggio, volume);
    return(0);
    }
    int calcola(float raggio, float *pt_area, float *pt_volume)
    {
    *pt_area=raggio*raggio*4.0*PI_GRECO;
    *pt_volume=raggio*raggio*raggio*4.0/3.0*PI_GRECO;
    return(0);
    }
     

  • Esempio - versione C++

  • /* sfera.cpp */
    #include <iostream.h>
    int main()
    {
    int calcola(float raggio, float &area, float &volume);
    float raggio;
    float area;
    float volume;
    int retcode;
    cout << "Digita il valore del raggio: ";
    cin >> raggio;
    retcode = calcola(raggio, area, volume);
    cout << "Area della sfera di raggio " << raggio << "=" << area << endl;
    cout << "Volume della sfera di raggio " << raggio << "=" << volume << endl;
    return(0);
    }
    int calcola(float raggio, float &area, float &volume)
    {
    const float PI_GRECO = 3.14159;
    area=raggio*raggio*4.0*PI_GRECO;
    volume=raggio*raggio*raggio*4.0/3.0*PI_GRECO;
    return(0);
    }

    Per evitare che un argomento, p.e. una struttura, passato per indirizzo, venga modificato, si deve specificare const:

    int prova(const Listino &st_Ricambi)
    {
    ...
    }


    Array e tipi enumerativi

    Un 'tipo enumerativo' (enum) è un elenco di costanti, p.e.:

    enum {scelta0, scelta1, scelta2};

    equivale a scrivere

    const int scelta0 = 0;
    const int scelta1 = 1;
    const int scelta2 = 2;

    in quanto enum assegna automaticamente i valori 0, 1, 2

    Un array è una sequenza di elementi di uno stesso tipo, indicizzati a partire da 0.

    Il numero di elementi viene indicato nella definizione, fra []:

    int prova[20]; //indice da 0 a 19

    Gli elementi dell'array possono essere indirizzati mettendo l'indice fra [], oppure, siccome il nome dell'array è un puntatore al primo elemento, sommando l'indice al nome, p.e.:

    a = prova[3];

    equivale a

    a = *(prova+3);

    L'inizializzazione di un array può avvenire alla definizione:

    int giorni_mese[12] = {31,28,31,30,31,30,31,31,30,31,30,31);

    oppure uno per uno, oppure, se possibile, in un ciclo.

    Una stringa è costituita da un'array di caratteri, quindi il suo nome è un puntatore al primo carattere; la stringa può dunque essere definita in due modi:

    char nome[20];
    char cognome[] = "Rossi";

    oppure

    char *nome;
    char *cognome = "Rossi";
     


    AppWizard: generazione di applicazioni
     
     

    Uso di AppWizard

    Provare ad eseguire le seguenti operazioni:
     

  • --- Menu/File - New
  • - MFC AppWizard (exe)
  • - Project name: un nome, p.e. 'prova' (viene creata la subdir 'prova' nella dir 'MyProjects')
  • - Step 1: Multiple Documents
  • - Step 2: No DB
  • - Step 3: No Compound, other:ActiveX
  • - Step 4: Features: Docking ToolBar
  • - Step 5: Comments, Shared DLLs
  • - Step 6: vengono visualizzate le classi create, p.e.:

  •  
    Classi generate da AppWizard
    Class name  Header file  Base Class  Implementation file
    CprovaApp prova.h  CWinApp prova.cpp
    CMainFrame MainFrm.h CMDIFrmWnd MainFrm.cpp
    CChildFrame ChildFrm.h CMDIChildWnd ChildFrm.cpp
    CprovaDoc provaDoc.h CDOcument provaDoc.cpp
    CprovaView provaView.h CView provaView.cpp

    (Le voci in corsivo non si possono modificare)

    (Se si vuole che il programma sia in grado di modificare files di testo, selezionare la classe CprovaView e modificare la BaseClass da 'CView' a 'CEditView')

    Premendo finish viene visualizzata una finestra informativa del tipo:
     
    Application type of prova:
    Multiple Document Interface Application targeting:
    Win32

    Classes to be created:
    Application: CProvaApp in prova.h and prova.cpp
    Frame: CMainFrame in MainFrm.h and MainFrm.cpp
    MDIChildFrame: CChildFrame in ChildFrm.h and ChildFrm.cpp
    Document: CProvaDoc in provaDoc.h and provaDoc.cpp
    EditView: CProvaView in provaView.h and provaView.cpp

    Features:
    + Initial toolbar in main frame
    + Initial status bar in main frame
    + Printing and Print Preview support in view
    + 3D Controls
    + Uses shared DLL implementation (MFC42.DLL)
    + ActiveX Controls support enabled
    + Localizable text in:
    Italiano [standard]


     

    Dopo l'OK AppWizard crea un file di risorse, una serie di file C++ e di header e alcune immagini bitmap;

    Alla fine viene visualizzata la finestra di WorkSpace, che permette di visualizzare:
     
    WorkSpace
    Classi Risorse Files Guida VisualC++
    CAboutDlg Accelerator Source files
    CChidFrame Dialog Header files
    CMainFrame Icon Resource files
    CprovaApp Menu readme.txt
    CprovaDoc String Table (globals)
    Cprovaview ToolBar

    (La finestra di WorkSpace si può disporre in verticale o in orizzontale)

    Compilazione

    Menu Build - Build prova.exe per compilare

    La compilazione genera files OBJ, che vengono uniti a codice prelevato dalle librerie;
    vengono quindi aggiunte le risorse (finestre di dialogo, menu, icone, ecc.) e viene creato il file eseguibile '.exe', che porà essere lanciato dall'esterno o dall'interno (Run)

    Viene creato anche un file README.TXT che descrive l'applicazione appena generata.

    L'applicazione 'prova' è in grado di creare, aprire, modificare, stampare uno o più files di testo; si possono aprire più finestre contemporaneamente. (p.e. si possono aprire due documenti, e fare Cut&Paste da uno all'altro)


    ClassWizard e WizardBar: modifica di applicazioni

    WizardBar contiene tre 'combo':

    La freccia in basso permette di scegliere l'azione da eseguire sul membro o sulla classe, e la bacchetta magica da' il via all'esecuzione.

    Ciascuna delle sei classi MFC elencate nella prima combo ha uno scopo ben definito, relativo ad una determinata parte dell'applicazione:

    Per modificare la finestra di dialogo informazioni:

    - Selezionare 'IDD_ABOUTBOX' fra le risorse 'Dialog' (Dialogo (IDD) relativo al menu ?(ABOUT))
    - Utilizzare i controlli per modificare la finestra di dialogo
    - Save
    - Rebuild All

    Per aggiungere una nuova finestra di dialogo:

    - Selezionare 'Insert Dialog' col tasto destro sulla cartella delle risorse Dialog

    Viene proposta una finestra di dialogo di default, con nome IDD_DIALOG1, che si può personalizzare con i controlli, che possono contenere:

    - immagini
    - testo statico
    - testo editabile
    - raggruppamenti
    - pulsanti
    - Check box
    - radio box
    - combo box
    - list box
    - scroll bar orizzontali
    - scroll bar verticali
    - spin
    - progress
    - slider
    - hot key
    - list control
    - tree control
    - tab control
    - animazioni
    - rich edit
    - custom control

    Per associare una classe alla nuova finestra di dialogo:

    - Doppio click sulla finestra di dialogo
    - Create new class - OK
    - Nome della classe (p.e.): CNuovaClasse: propone nome file=NuovaClasse.cpp,
    eredita la 'Base Class' CDialog (perchè ClassWizard è stato chiamato da una finestra di dialogo).

    Alla nuova classe viene associata la finestra di dialogo 'chiamante', p.e. IDD_DIALOG1.

    IDD è il prefisso che si usa di solito per le finestre di dialogo.

    - OK, OK

    Per inserire in un menu la chiamata alla nuova classe:

    - Doppio click sulla risorsa IDR_(nome_pgm)TYPE (p.e.IDR_PROVATYPE) nella cartella dei menu (Esiste anche un altro menu, IDR_MAINFRAME, che è relativo alla finestra principale e viene visualizzato quando non c'è nessun documento aperto.
    - Scegliere una casella vuota in fondo a qualcuno dei menu, oppure usare INS per inserire una nuova voce
    - Click destro sulla casella vuota, inserire Caption e Prompt
    - Chiudere e riaprire per vedere l'ID della nuova voce di menu, p.e. ID_UITEM32771
    - Se si ricompila il programma ora, sarà presente la nuova voce di menu, ma non sarà attiva

    Per agganciare al programma la nuova finestra di dialogo:

            ONMENUITEM32771         (nome_classe).DoModal();
            p.e. CNuovaClasse().DoModal();

            per chiamare la funzione DoModal() (ereditata da CDialog) all'interno della classe appena creata per gestire la finestra di dialogo

            #include "(nome_classe senza C).h"
            #include "NuovaClasse.h"

    Torna a indice Guide