| prof. Nunzio Brugaletta |
C++:
programmazione e oggetti |
Applicare il metodo top-down alla risoluzione di un problema vuol dire risolvere il problema, in una primo approccio, come se il linguaggio utilizzato mettesse a disposizione istruzioni di alto livello che riescono a svolgere una parte del problema e, successivamente, passare ad occuparsi della risoluzione delle singole parti.
Come applicazione viene proposto un esempio di selezione: dato un vettore di interi non nulli, si vuole generare il sottoinsieme dei pari.
Il primo passo da compiere è stabilire quali sono le fasi che portano alla soluzione del problema:
#include <iostream> /*1*/
#include <vector> /*1*/
using namespace std;
// prototitpi
int main()
{
vector<int> numeri, pari; /*2*/
cout << "Estrazione di sottoinsieme:" << endl
<< "data una sequenza di interi positivi" << endl
<< "comunica il sottoinsieme dei pari" << endl;
// input numeri da elaborare
// estrazione sottoinsieme dei pari
// output sottoinsieme pari
return 0;
}
In questa prima stesura, a parte le inclusioni che servono (1) e la dichiarazione delle variabili necessarie alla risoluzione del problema (2), sono presenti soltanto righe di commento utilizzate per stabilire quali cose fare e in quale ordine.
Stabilita, per grandi linee, la sequenza delle funzioni da svolgere, si passa a chiarire meglio la prima funzione: quella che si deve occupare dell'input dei numeri da elaborare. In questa sede è importante solo stabilire cosa la funzione deve fare e come si deve utilizzare.
Cosa fa la funzione: la funzione, che potrà avere nome inputNumeri, dovrà occuparsi dell'input da tastiera dei numeri da elaborare.
Come si utilizza la funzione: la funzione non ha bisogno di input (non gli serve niente per potere assolvere ai propri compiti). Fornisce, in output (dati che rende disponibili come risultati della propria elaborazione), il vettore caricato con i dati acquisiti da tastiera.
In conseguenza, a quanto osservato, si potrà aggiungere al programma il prototipo e la chiamata alla funzione:
#include <iostream>
#include <vector>
using namespace std;
// prototitpi
vector<int> inputNumeri(); /*1*/
int main()
{
vector<int> numeri, pari;
cout << "Estrazione di sottoinsieme:" << endl
<< "data una sequenza di interi positivi" << endl
<< "comunica il sottoinsieme dei pari" << endl;
// input numeri da elaborare
numeri = inputNumeri(); /*2*/
// estrazione sottoinsieme dei pari
// output sottoinsieme pari
return 0;
}
Nel prototipo (1) è evidenziato il fatto che la funziona ritorna un oggetto di tipo vector<int>. Nella chiamata alla funzione (2), main assegna il valore di ritorno della funzione a numeri in cui si ritroveranno i valori acquisiti dalla funzione.
Con lo stesso procedimento si stabiliscono i compiti e le modalità d'uso delle rimanenti due funzioni:
La funzione che si deve occupare dell'estrazione del sottoinsieme di pari, e che potrà avere nome estraiPari, ha necessità di conoscere il vettore da cui estrarre il sottoinsieme (per la funzione è un input e quindi sarà un parametro passato per valore dal main) e produrrà (unico output per la funzione e, quindi, valore di ritorno della funzione) il vettore sottoinsieme.
La funzione che dovrà occuparsi dell'output su video del sottoinsieme, e che potrà avere nome outputPari, dovrà conoscere (input, quindi parametro passato per valore) il vettore da visualizzare. Non produce dati da tornare a main. Fra l'altro è pure l'ultima istruzione che viene eseguita. Non saranno necessari parametri in uscita.
Il programma, con i prototipi e le chiamate alle funzioni, sarà:
#include <iostream>
#include <vector>
using namespace std;
// prototitpi
vector<int> inputNumeri();
vector<int> estraiPari(vector<int>);
void outputPari(vector<int>);
int main()
{
vector<int> numeri, pari;
cout << "Estrazione di sottoinsieme:" << endl
<< "data una sequenza di interi positivi" << endl
<< "comunica il sottoinsieme dei pari" << endl;
// input numeri da elaborare
numeri = inputNumeri();
// estrazione sottoinsieme dei pari
pari = estraiPari(numeri);
// output sottoinsieme pari
outputPari(pari);
return 0;
}
Il programma è formalmente completo: sono specificate le funzioni che assolve e la sequenza delle fasi di elaborazione. Naturalmente per poterlo compilare e, successivamente, eseguire è necessario aggiungere il codice delle funzioni. Finora si è specificato cosa le funzioni fanno, ora dovrà essere specificato come lo fanno, ovvero si dovrà aggiungere la definizione delle funzioni.
...
// prototitpi
vector<int> inputNumeri();
vector<int> estraiPari(vector<int>);
void outputPari(vector<int>);
int main()
{
...
}
// input numeri da elaborare
vector<int> inputNumeri()
{
vector<int> num;
int temp;
cout << "Numero da elaborare (0 per finire) ";
cin >> temp;
while(temp){
num.push_back(temp);
cout << "Numero da elaborare (0 per finire) ";
cin >> temp;
}
return num;
}
// estrazione sottoinsieme pari
vector<int> estraiPari(vector<int> num)
{
vector<int> numpari;
int i;
for(i=0;i<num.size();i++){
if(!(num.at(i)%2)) /*1*/
numpari.push_back(num.at(i)); /*2*/
}
return numpari;
}
// output sottoinsieme pari
void outputPari(vector<int> numpari)
{
int i;
cout << "Sottoinsieme pari" << endl;
for(i=0;i<numpari.size();i++)
cout << " " << numpari.at(i);
cout << endl;
}
La funzione che genera il sottoinsieme dei pari, esamina il vettore da elaborare e se trova un elemento pari (controllo in 1), lo carica nel vettore dei pari (2).
Le altre funzioni, per la semplicità del codice, non necessitano di ulteriori commenti.
| http://ennebi.solira.org |
ennebi@solira.org |