sabato 5 gennaio 2013

Organizzare il proprio codice

Quando viene programmato un gioco, il codice è pieno di funzioni e classi, le quali possono diventare ingestibili in un singolo file. Inoltre è utile riutilizzare parte dei propri programmi, ad esempio alcune classi e funzioni, come base per successivi programmi in C++. Bisogna quindi spezzare il codice in pezzi maneggevoli e utili attraverso file multipli. Generalmente si separano le funzioni relative o le singole classi in un file proprio.

Il programma Roditore

Il programma Roditore non è composto da un solo file, è una collezione di tre files che lavorano insieme per creare una singola applicazione. Si tratta di un progetto molto semplice. Viene instanziato un solo roditore, il quale dice “ciao”. Questo esempio dimostra come sia possibile spezzare il programma in file multipli.

Usare un file

E' possibile creare questo semplice programma con un singolo file di codice, in quanto piuttosto corto, come mostrato sotto.
#include<iostream>
using namespace std;
class Roditore
{ public: void Saluto();
};
void Roditore::Saluto()
{ cout << “Ciao, Io sono un roditore.\n”; }
int main()
{ cout << “Creare un oggetto Roditore.\n”;
Roditore ctopo;
ctopo.Saluto();
return 0;
}

Comunque, è possibile spezzare questo file in file multipli che lavorano assieme come un progetto, come viene fatto di seguito. In questo progetto sono creati 3 files.
  • File intestazione. Contiene solo la definizione della classe Roditore.
  • File implementazione. Contiene l'implementazione delle funzioni membro della classe Roditore.
  • File applicazione. Contiene il programma, con la funzione main(), la quale usa la classe Roditore presente nei file implementazione e intestazione. Questo file viene eseguito dal compilatore.

Creare un file intestazione (Header)

I file header sono creati per essere inclusi in altri file. Si è già parlato di file intestazione in quanto ogni programma già presentato include almeno un file header proveniente dalla libreria standard, <iostream>. Quando si spezza il programma in file multipli, generalmente si scrive un proprio file intestazione e solitamente lo si fa per ogni classe. Questo file include solo la definizione della classe, non la sua implementazione.
//roditore.h
//file intestazione
#ifndef RODITORE_H
#define RODITORE_H
class Roditore
{ public: void Saluto();
};
#endif

La definizione della classe Roditore è molto semplice, in quanto dichiara una sola funzione pubblica, Saluto(). Vi sono alcuni concetti nuovi nel codice. Le tre linee che iniziano per # sono direttive del preprocessore, in pratica istruzioni per il compilatore. Insieme dicono al compilatore cosa non includere nella definizione di Roditore del progetto se sono già state incluse in esso. Viene presa questa precauzione per evitare che la stessa classe sia definita più di una volta nel codice, questo risulta in un errore. Cosa sta succedendo? La prima direttiva dice che se il simbolo RODITORE_H non è stato definito (in una lista di simboli che il compilatore conserva per compilare il codice), il programma deve andare avanti e processare tutto il codice che segue, sino al marcatore della terminazione.
#ifndef RODITORE_H
Se il simbolo è sulla lista, il programma deve saltare tutto il codice che segue, sino al marcatore di terminazione. Il marcatore di fine è l'ultima direttiva presente sul file.
#endif
La prima volta che roditore.h il file intestazione viene incluso nel processo, esso viene compilato, RODITORE_H non è nella lista dei simboli, e vien inclusa la definizione della classe Roditore. Inoltre il compilatore processa la direttiva, la quale chiede di includere il simbolo RODITORE_H nella sua lista di simboli.
#define RODITORE_H
Questo significa che se vien fatto un altro tentativo di includere questo file intestazione nel progetto, il compilatore dopo aver visto il simbolo RODITORE_H nella lista, salterà la definizione della classe Roditore, senza tentare di definirla un'altra volta. Comunque il simbolo RODITORE_H che viene scelto per il file d'intestazione nasce da una convenzione, per la quale il nome del file viene scritto in maiuscole seguite da _H. Questa convenzione ci permette di definire un simbolo unico per ogni file intestazione. Inoltre è quello che ogni altro programmatore si aspetta di trovare scritto.

Creare il file implementazione

Poiché il file intestazione contiene solo la definizione della classe, i dati di implementazione della classe devono essere immagazzinati in un altro file. Questo file deve avere lo stesso nome del file intestazione, ma la sua estensione è la familiare .cpp. L'implementazione di roditore.h viene chiamata roditore.cpp. Di seguito si riporta il codice.
//roditore.cpp
//file implementazione
#include<iostream>
#include “roditore.h”
using namespace std;
void Roditore::Saluto()
{ cout << “Ciao, Io sono un roditore.\n”; }

Il file contiene l'implementazione di Roditore::Saluto(). Inoltre include la definizione delle variabili e dei membri statici. Da notare l'istruzione con la quale viene incluso il file intestazione:
#include “roditore.h”
Quando si effettua un'inclusione, è come se una copia venga incollata direttamente dove si trova l'istruzione include. Includendo roditore.h si completa la definizione della classe. Questi due file insieme rappresentano un modo pulito per memorizzare una singola classe. Il passo successivo è usare la classe in un programma reale.

Creare file applicazione

Si possono includere i propri file intestazione nell'applicazione usando l'istruzione include. Viene incluso roditore.h in una semplice applicazione. Di seguito viene riportato il codice.
//roditore_app.cpp
//file applicazione
#include<iostream>
#include “roditore.h”
using namespace std;
int main()
{  cout << “Creare un oggetto Roditore.\n”;
    Roditore ctopo;
    ctopo.Saluto();
 return 0;
}

Quando viene compilato il programma, il compilatore legge la seguente linea di codice e la definizione della classe Roditore memorizzata nei file roditore.h e roditore.cpp.
#include “roditore.h”
Come se il codice di definizione fosse stato aggiunto al programma. Pertanto durante l'esecuzione, l'oggetto Roditore viene fatta istanza e la funzione dice ciao.

 

Nessun commento:

Posta un commento