Classi

Introduzione alle classi

La più importante caratteristica del C++, che lo rende un linguaggio per la programmazione orientata agli oggetti, è la possibilità offerta al programmatore di definire un nuovo tipo attraverso un meccanismo chiamato Classi

Mentre la dichiarazione di un tipo predefinito è chiamata variabile, la dichiarazione (o istanza) di una classe è chiamata Oggetto

Prima di descrivere com'è fatta una classe, si consideri il modo in cui si crea un nuovo tipo di dato in C.


Creazione di un nuovo tipo di dato in C
Ad esempio, si ha bisogno di scrivere un programma C che fa un intenso uso di date. Si potrebbe creare un nuovo tipo di dato in grado di rappresentare le date, usando la seguente struttura:

struct Data {

int giorno;

int mese;

int anno;

};

I campi membro di questa struttura sono mese, giorno, e anno. Per memorizzare una data si devono assegnare i valori corretti ai campi della struttura:

struct Data unaData;

unaData.giorno = 23;

unaData.mese = 1;

unaData.anno = 1985;

Non si può stampare una tale data passando la struttura a printf. Bisogna stampare ciascun campo della struttura separatamente, oppure si deve scrivere una funzione che riceve la data come parametro e la stampa, come nel seguente esempio:

void mostraData( struct Data *dt ) {

  static char *nomeMese[] = {

      "zero", "Gennaio", "Febbraio", "Marzo",

      "Aprile", "Maggio", "Giugno", "Luglio", "Agosto",

      "Settembre","Ottobre","Novembre","Dicembre"

      };

    printf( "%d-%s-%d", dt->giorno, nomeMese[dt->mese], dt->anno );

}

Questa funzione stampa il contenuto di una struttura "data", trasformando il numero del mese nel nome e stampando i campi della data.

Per eseguire operazioni sulle date, come ad esempio il confronto tra due di esse, si dovrebbero confrontare i singoli campi della struttura, oppure si potrebbe scrivere una funzione che riceva le due strutture come parametri e effettui il confronto.

Quando si definisce una struttura in C si crea un nuovo tipo. Quando si scrivono funzioni che operano su quella struttura si creano le operazioni ammesse su quel tipo di dato.

Questa tecnica per gestire le date ha dei difetti:

Un programmatore esperto riesce a prevenire questi inconvenienti, perchè sicuramente ha già vissuto le conseguenze derivanti dalla necessità di apportare modifiche ad un programma.


Creazione di un nuovo tipo di dato in C++
In C++ si definiscono sia i dati che le operazioni su di essi dichiarandoli in una classe.

Dichiarazione della classe
La dichiarazione di una classe assomiglia alla dichiarazione di una struttura, con la differenza che, la classe, contiene anche le funzioni. La seguente è una versione della classe Data:

// La classe Data

class Data {

  public:

    Data( int g, int m, int a ); // Costruttore

    void mostra(); // funzione per stampare la data

    ~Data(); // Distruttore

  private:

    int giorno, mese, anno; // campi privati

    // alcune funzioni utili:

    inline int max( int a, int b) {

      if( a > b ) return a;

      return b;

    }

 

    inline int min( int a, int b) {

      if( a < b ) return a;

      return b;

    }

};

Questa dichiarazione di classe corrisponde alla combinazione di una dichiarazione di struttura più un insieme di prototipi di funzione. Essa dichiara quanto segue:

Ecco le definizioni delle funzioni membro:

 

// - - - - - - il costruttore

Data::Data( int g, int m, int a ) {

  static int lung[] = { 0, 31, 28, 31, 30, 31, 30,

      31, 31, 30, 31, 30, 31 };

  mese = max( 1, m );

  mese = min( mese, 12 );

  giorno = max( 1, g );

  giorno = min( giorno, lung[mese] );

  anno = max( 1, a );

}

// - - - - - - Funzioni membro per stampare date

 

void Data::mostra() {

  static char *nomeMese[] = {

      "zero", "Gennaio", "Febbraio", "Marzo",

      "Aprile", "Maggio", "Giugno", "Luglio", "Agosto",

      "Settembre","Ottobre","Novembre","Dicembre"

  };

  cout << giorno << ' ' << nomeMese[mese] << ' ' << anno;

}

 

// - - - - Il distruttore

Data::~Data() {

// non fa nessuna operazione

}

La funzione mostra è familiare, ma le funzioni Data() e ~Data() sono nuove. Sono chiamate il Costruttore e il Distruttore e servono per creare e distruggere oggetti.

Queste non sono tutte le funzioni membro che una classe Data potrebbe richiedere, ma sono sufficienti per mostrare la sintassi di base per scrivere una classe.

Ecco un programma che usa la classe Data:

void main() {

  Data unaData( 3, 12, 1985 ); // Dichiara una data

  Data altraData( 23, 259, 1966 ); // Dichiara una data impossibile

  unaData.mostra();

  cout << endl;

  altraData.mostra();

  cout << endl;

}


Usare la Classe
Dopo aver definito una classe, si possono dichiarare una o più istanze di quella classe, esattamente come si fa con i tipi predefiniti.

Nell'esempio precedente. la funzione main dichiara due istanze della classe Data chiamate unaData e altraData. Questi sono oggetti, e ciascuno di essi contiene i valori di giorno, mese ed anno.

Nella dichiarazione di un oggetto potebbe esserci un elenco di parametri che servono per assegnare i valori iniziali alle proprietà della classe. Ad esempio, nella dichiarazione degli oggetti unaData e altraData sono presenti i valori iniziali, che verranno passati al costruttore, allo scopo di assegnarli ai campi membro. Si noti la sintassi per stampare il contenuto degli oggetti di classe Data.

In C si sarebbe dovuto passare la struttura come parametro:

mostraData( &unaData );
mostraData( &altraData );

In C++ si richiama la funzione membro, o metodo, usando l'operatore di accesso: ".", come nell'esempio seguente:

unaData.mostra();

altraData.mostra();

Queste espressioni evidenziano la stretta relazione tra il tipo Data e le funzioni che operano su di esso. Fa capire che l'operazione mostra() è parte della classe Data.

Comunque questo legame tra la classe e le sue funzioni compare solo nella sintassi. I singoli oggetti di classe Data non contengono una propria copia delle funzioni, essi contengono solo i campi membro.


Membri della classe (Attributi)
Si osservi la dichiarazione della classe Data:

class Data {

public:

  Data( int g, int m, int a ); // Costruttore

  void mostra(); // funzione per stampare la data

  ~Data(); // Distruttore

private:

  int giorno, mese, anno; // campi privati

}

Una dichiarazione di classe differisce dalla dichiarazione di una struttura nei seguenti modi:

Di seguito vengono esaminate queste tre differenze.

Visibilità dei campi membro
I termini private e public all'interno della definizione della classe specificano la visibilità dei membri che seguono. Tutti i campi che seguono un termine hanno la visibilità specificata, fino a quando si incontra un termine diverso, oppure fino alla fine della definizione della classe. I campi privati sono accessibili solo dalle funzioni membro della classe. Questi definiscono lo stato interno della classe.

I campi pubblici sono accessibili sia dalle funzioni membro della classe sia da tutte le altre funzioni del programma che hanno un'istanza della classe nella loro regione di visibilità. I campi pubblici rappresentano le funzionalità che la classe mostra al resto del programma, in altri termini si dice che essi sono l'interfaccia della classe.

La classe Data dichiara che i suoi tre campi membro sono privati, ovvero sono visibili solo alle funzioni membro della classe. Se un'altra funzione tenta di accedere a uno di questi campi privati il compilatore segnala un errore. Per esempio, si supponga di accedere a un campo privato di un oggetto di classe Data:

void main() {

  int i;

  Data unaData( 3, 12, 1985 );

  i = unaData.mese; // Errore: non è ammesso leggere un campo privato

  unaData.giorno = 1; // Errore: non è ammesso scrivere in un campo privato

}

Al contrario, la funzione mostra() è pubblica, quindi è visibile alle funzioni esterne alla classe.

Sebbene sia ammesso usare, anche ripetendo, i termini public e private dovunque all'interno della classe, conviene raggruppare tutti i campi pubblici e tutti i campi privati e poi tutti metodi pubblici e tutti i metodi privati. Se manca la specifica, si assume che i campi siano privati. Ma è preferibile specificarlo ugualmente.

La classe Data mostra una regola importante da rispettare nella programmazione orientata agli oggetti: L'interfaccia pubblica contiene solo funzioni. Un campo membro privato deve essere letto o modificato solo chiamando una apposita funzione membro pubblica.

Funzioni membro
La classe Data ha una funzine membro denominata mostra(), che serve a stampare i campi membro. Si noti che la funzione è dichiarata e anche definita. Il prototipo della funzione appare all'interno della dichiarazione della classe Data e quando la funzione è definita è indicata con: Data::mostra( ). Questa notazione indica che la funzione è membro della classe e che il suo nome rientra nella regione di visibilità della classe. L'operatore "::" è detto scope resolution, cioè indicatore della regione di visibilià.

Le funzioni membro possono essere ridefinite, purchè restino distinguibili in base ai parametri.

La funzione membro mostra() non riceve parametri, perchè ha libero accesso ai campi membro dell'oggetto. Per esempio:

unaData.mostra();

altraData.mostra();

Nella prima istruzione la funzione mostra() accede ai campi dell'oggetto unaData, nella seconda istruzione la funzione mostra() accede ai campi dell'oggetto altraData. La funzione usa i campi dell'oggetto a cui appartiene.

Una funzione membro può essere chiamata anche tramite un puntatore a un oggetto, usando l'operatore ->. Per esempio:

Data unaData( 3, 12, 1985 );

Data *ptrData = &unaData;

ptrData->mostra();

In questo segmento di programma, viene dichiarato un puntatore ad un oggetto Data e poi si richiama la funzione mostra() tramite quel puntatore.

Una funzione membro può essere chiamata tramite il riferimento ad un oggetto. Per esempio:

Data unaData( 3, 12, 1985 );

Data &altraData = unaData;

altraData.mostra();

Qui la funzione mostra() viene chiamata tramite il riferimento altraData. Siccome altraData è un sinonimo di unaData, la funzione mostra() stampa il contenuto di unaData.

Queste tecniche descritte per chiamare una funzione valgono solo se la funzione è pubblica. Se una funzione è dichiarata private, può essere chiamata solo dalle funzioni della stessa classe. Per esempio:

class Data {

public:

  void mostra(); // funzioni Pubbliche

  // ...

private:

  int giorniTrascorsi(); // funzioni Private

  // ...

};

// - - - - - - - mostra la data nella forma "ggg AAAA"

void Data::mostra() {

  cout << giorniTrascorsi() << " " << anno; // chiama una funzione privata

}

// - - - - Calcola il numero di giorni trascorsi

int Data::giorniTrascorsi() {

  int totale = 0;

  static int lung[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

  for( int i= 1; i<= mese; i++ )

    totale += lung[i];

  totale += giorno;

  return totale;

}

Notare che la funzione mostra() chiama direttamente la funzione giorniTrascorsi(), senza specificare l'oggetto, perchè una funzione membro può usare campi e funzioni dell'oggetto a cui appartiene.


Una classe per elaborare una lista concatenata.

Una lista concatenata offre alcuni vantaggi rispetto agli array

Una lista non ha una dimensione massima, quindi non si ha spreco di spazio inutilizzato o, viceversa, non succede che un elemento non trova posto perché si è esaurito lo spazio. Inoltre in una lista gli elementi possono essere inseriti o eliminati senza alterare la posizione degli altri elementi.

Una lista si definisce concatenata perché ogni elemento contiene il puntatore al successivo elemento. Si supponga che gli elementi contenuti nella lista siano di tipo intero. I metodi di una classe Lista sono:

MetodoOperazioneParametro ricevutoParametro restituito
Lista ()costruttore senza parametrivoidvoid
Lista costruttore copiaListavoid
~Lista distruttorevoidvoid
Inserisci() Inserisce un elemento in testa alla listaTipo dell'elemento di lista
NumeroElementi()Restituisce il numero degli elementi contenuti nella listavoid int
Svuota()Elimina tutti gli elementi contenuti nella listavoidvoid
Elimina()Elimina il primo elemento della lista, se contenuto, che è uguale a quello specificato Tipo dell'elemento di listavoid
Stampa()Stampa tutti gli elementi contenuti nella listavoidvoid
Ricerca()Indica se un dato elemento è contenuto nella lista Tipo dell'elemento di listabool

il file Lista.h

Nr.
linea
Commento
3Si dichiara che Record è una struttura.
4, 5Si dichiarano due nuovi tipi, uno è un puntatore a Record, l'altro è un nome associato al tipo intero.
6Dichiarazione della classe Lista.
8, 9Campi privati. primo è un puntatore a una struttura. Conteggio è un intero.
10Si ridefinisce l'operatore di assegnazione (da usare quando uno degli operandi è una lista).
12il costruttore.
13Il costruttore copia.
14Il distruttore.
15Il metodo Inserisci riceve il riferimento au intero, che non può modificare e provvede a inserirlo in testa alla lista.
16La funzione restituisce il numero di elementi che fanno parte della lista.
17Il metodo Svuota cancella tutti gli elmenti della lista.
18Il metodo Elimina toglie dalla lista il primo elemento che è uguale al parametro ricevuto.
19Il metodo Stampa scandisce la lista e stampa il valore degli elementi.
20Il metodo Ricerca restituisce un risultato booleano per indicare se il parametro ricevuto è presente nella lista.

il file Lista.cpp: il costruttore

Nr.
linea
Commento
4-7Si definisce la struttura Record: contiene un campo dato e un campo puntatore al successivo.
8, 9, 10Il costruttore assegna i valori iniziali ai campi della classe.


il file Lista.cpp: il costruttore copia

Nr.
linea
Commento
12Lista(const Lista& lst)

Il costruttore Copia riceve il riferimento ad una lista, che non viene modificata (const):

L'oggetto lst ricevuto come parametro:
13if ((this != &lst) && primo)

Se il riferimento ricevuto (lst) non punta alla stessa lista e la lista lst contiene almeno un elemento (primo diverso da 0) si procede con la copia della lista lst in questa lista.
14primo = new Record

Si crea un nuovo record e si raccoglie il suo puntatore nel campo primo della classe

15primo->dato = lst.primo->dato

Nella sezione dato del nuovo record si copia il valore contenuto nel corrispondente elemento della lista da copiare
16PRec lp = lst.primo

Si crea un nuovo puntatore a Record e lo si inizializza con il puntatore al primo Record della lista da copiare.

17PRec p = primo

p è un puntatore a Record inizializzato con il puntatore al primo Record della lista in cui copiare gli elementi.

18while (lp->successivo)

Si avanza nella lista da copiare, fintanto che non si raggiunge il puntatore 0
19p->successivo = new Record

Si aggiunge un nuovo record alla lista in cui copiare il nodo dalla lista sorgente lst.


Il puntatore al nuovo nodo viene scritto nel campo successivo del record puntato da p
20p = p->successivo

Si passa al nodo successivo.

21, 22lp = lp->successivo
p->dato = lp->dato


Si avanza nella lista sorgente e si copia il campo dalla lista sorgente alla lista destinazione.

24p->successivo = 0

Quando si raggiunge la fine della lista sorgente si assegna il valore 0 anche al puntatore contenuto nell'ultimo record della lista, per indicare la fine della lista.


il file Lista.cpp: il distruttore




il file Lista.cpp: il metodo Inserisci

Nr.
linea
Commento
30Inserisci(const Elemento& el)

Il metodo Inserisci riceve il riferimento ad un intero, che non viene modificato (const):
31PRec p = new Record

Viene creato un nuovo nodo e il puntatore viene mamorizzato in p
32p->dato = el

nel canpo dato del nuovo nodo viene memorizzato il valore ricevuto come parametro.

il file Lista.cpp: il metodo Stampa

Nr.
linea
Commento
38PRec p = primo

Si dichiara un puntatore locale alla struttura Record e lo si inizializza con il puntatore alla testa della Lista.
39while (p) {

si entra in un ciclo che si ripete se p è diverso da 0.
40cout << p->dato << " - "

si stampa il valore contenuto nel campo dato del nodo.
41p = p->successivo

si avanza nella lista, leggendo il puntatore al nodo successivo e assegnandone il valore al puntatore p.
42si ritorna al test di ripetizione del ciclo while

il file Lista.cpp: il metodo NumeroElementi

Nr.
linea
Commento
45Il metodo NumeroElementi restituisce il numero di elementi contenuti nella Lista.

Nr.
linea
Commento
48PRec cancella

si dichiara un puntatore a Record.
49while (primo) {

si entra in un ciclo a condizione che il puntatore al primo elemento della lista sia diverso da 0.
50cancella = primo

si effettua una copia del puntatore al primo elemento della lista.
51primo = primo->successivo

il successivo elemento diventa il nuovo elemento di testa della lista, eliminando così dalla lista il primo elemento che è puntato dal puntatore cancella.
52delete cancella

si elimina lo spazio occupato dal nodo estratto dalla lista.
54conteggio = 0

Al termine del ciclo il campo membro conteggio viene posto a 0.

il file Lista.cpp: il metodo Elimina

Nr.
linea
Commento
56Elimina(const Elemento& el) {

il metodo riceve come parametro il riferimento a un intero, che rappresenta il valore che si vuole eliminare dalla lista.
57if(primo) {

se la lista non è vuota.
58if (primo->dato == el) {

se il primo elemento della lista contiene il valore ricevuto come parametro.
59PRec cancella = primo

si salva il puntatore al primo elemento della lista.
60primo->successivo

si passa al successivo elemento.
61delete cancella

si elimina lo spazio occupato dal nodo.
62conteggio--

si conta un elemento in meno.
63altrimenti si entra in un ciclo di scansione della lista, alla ricerca del nodo il cui campo dato sia uguale al parametro el

il file Lista.cpp: il metodo Ricerca

Nr.
linea
Commento
79bool Ricerca(const Elemento& el) {

il metodo riceve come parametro il riferimento a un intero, che rappresenta il valore che si vuole eliminare dalla lista e restituisce un valore booleano.
80PRec p = primo

Si accede alla lista.
81bool trovato = false

si crea una variabile booleana.
82while ((p) && (!trovato)) {

Si scandisce la lista, a condizione che l'elemento non sia stato trovato e non si sia raggiunta la fine della lista.
83, 84if (p->dato ==el)
trovato = true


Se il nodo raggiunto contiene il valore cercato si ritorna true.
86p = p->successivo

altrimenti si avanza nella lista.

il file ElaboraLista.cpp per il collaudo della classe

Nr.
linea
Commento
5La funzione StampaMenu()verrà richiamato per proporre le possibili operazioni ammesse sulla lista.


il file ElaboraLista.cpp per il collaudo della classe (continuazione)

Nr.
linea
Commento
19, 20vengono dichiarate due variabili
21Lista lista

viene dichiarata l'istanza lista della classeLista
21 

22do {

Si entra in un ciclo
23StampaMenu()

viene richiamata la funzione per mostrare il menu
24cin >> i

la scelta avviene introducendo un numero da tastiera e premendo invio. Il tasto premuto viene acquisito in formato carattere
25switch(c) {

a seconda del carattere il flusso del programma subisce una diramazione verso l'operazione scelta
56, 61Si deve notare che (linea 57) viene creata una seconda istanza della classe Lista richiamando il costruttore copia (quello con un parametro di ingresso). Le operazioni sono inserite in un blocco in modo che al termine dell'uso della lista copiata venga richiamato il distruttore.

Una classe per elaborare un albero binario

L'albero che si propone nel seguente esercizio memorizza, in ogni nodo, numeri interi.

Per ogni nodo, a sinistra ci sono i valori minori e a destra i valori maggiori del valore contenuto nel nodo.
Esempio:

il file Albero.h

Nr.
linea
Commento
3questa dichiarazione serve ad informare il compilatore che l'identificatore Nodo è una struttura.
4, 5l'identificatore pNodo è di tipo "puntatore a Nodo". (il compilatore ha appreso nella linea precedente il tipo dell'identificatore Nodo) e Elemento è un nuovo tipo di variabile intera.
6Alberobinario è una classe.
8radice è di tipo pNodo (come definito alla linea 4).
9, 15Sezione dei metodi privati
17, 25Sezione dei metodi pubblici

il file Albero.cpp: Definizione della struttura Nodo

Nr.
linea
Commento
4Nodo è una struttura.
7il campo che contiene l'informazione è costituito da un intero.
8, 9Ogni nodo dell'albero ha due puntatori ai nodi successori.


il file Albero.cpp: il costruttore e il distruttore

Nr.
linea
Commento
2Il costruttore assegna il valore iniziale zero al puntatore alla radice dell'albero, per indicare che l'albero è vuoto.
5Il distruttore richiama il metodo privato Svuota per rilasciare la memoria occupata dai nodi creati dinamicamente.


il file Albero.cpp: il metodo AggiungiElem

Nr.
linea
Commento
1Il metodo AggiungiNodo riceve il riferimento ad un valore da memorizzare nell'albero.
2Richiama il metodo AggiungiElem passando il riferimento alla radice dell'albero e il riferimento al valore da inserire.
5la prima volta che la funzione viene richiamata la radice vale zero.
Quando l'albero contiene almeno un elemento il riferimento al nodo è diverso da zero quindi verrà eseguito il ramo else .
6 - 9viene creato un nuovo nodo, viene inizializzato con il dato ricevuto e con i due puntatori a zero. Si deve notare che il parametro n è dichiarato come riferimento quindi, la prima volta, alla linea 6 viene modificato anche il valore di radice, o comunque del puntatore contenuto nel nodo genitore.
11si deve decidere se il nodo deve essere inserito nel sotto albero di destra o di sinistra.
12 - 14Avviene una chiamata ricorsiva alla funzione, accedendo ad uno dei due sottoalberi del nodo.



il file Albero.cpp: il metodo inAlbero

Nr.
linea
Commento
1riceve, come parametro, un valore e restituisce un valore logico per indicare se il valore è presente nell'albero.
5se si raggiunge un nodo terminale significa che il valore non è stato trovato.
7, 8se il valore cercato corrisponde al valore contenuto nel nodo si restituisce true
10, 12altrimenti si richiama ricorsivamente la funzione passando il puntatore al sottoalbero appropriato.

il file Albero.cpp: il metodo Sostituisci

Nr.
linea
Commento
1il metodo Sostituisci riceve il puntatore n alla radice di un albero e il puntatore p ad un nodo da sostituire
2q è il puntatore a un nodo
3se il sottoalbero destro è vuoto
4copia il puntatore al nodo corrente
5con n avanza nel sottoalbero sinistro
6nel puntatore a sinistra del sottoalbero corrente copia il puntatore a sinistra contenuto nel nodo da sostituire
7nel puntatore a destra del sottoalbero corrente copia il puntatore a destra contenuto nel nodo da sostituire
8il puntatore al nodo da sostituire viene aggiornato con il puntatore al nodo corrente.
10altrimenti (se il sottoalbero destro non è vuoto) richiama ricorsivamente la funzione passando come parametri il sottoalbero destro e il nodo da sostituire. La condizione di arresto della chiamata ricorsiva è che il sottoalbero destro sia vuoto.

il file Albero.cpp: il metodo Elimina

Nr.
linea
Commento
1il metodo Elimina riceve il puntatore alla radice dell'albero e il valore dell'elemento da eliminare
2se non si è raggiunta una foglia
3e se il campo dato è uguale al valore cercato
4copia il puntatore al nodo corrente
5se il sottoalbero sinistro del nodo da eliminare è vuoto
6sostituisci il nodo con il sottoalbero destro
8altrimenti se il sottoalbero destro del nodo da eliminare è vuoto
9sostituisci il nodo con il sottoalbero sinistro
10il nodo da eliminare ha entrambi i sottoalberi
11richiama la funzione Sostituisci
12cancella il nodo
13se il campo dato è diverso dal valore da eliminare
14se il valore da eliminare è maggiore del valore contenuto nel campo dato
15richiama ricorsivamente la funzione accedendo al sottoalbero destro
17altrimenti richiama ricorsivamente la funzione accedendo al sottoalbero sinistro

il file Albero.cpp: il metodo Svuota

Nr.
linea
Commento
2Se il sottoalbero non è vuoto
3, 4richiama ricorsivamente la funzione svuota passando il puntatore a uno dei due sottoalberi
5al ritorno dalla funzione elimina il nodo

il file Albero.cpp: visita il ordine anticipato

Nr.
linea
Commento
2se non si è raggiunta una foglia
3stampa il dato
4avanza a sinistra
5quando si è esaurito il sottoalbero sinistro avanza nel sottoalbero destro

il file Albero.cpp: visita il ordine differito

Nr.
linea
Commento
2se non si è raggiunta una foglia
3avanza nel sottoalbero sinistro
4quando si è esaurito il sottoalbero sinistro avanza nel sottoalbero destro
5mostra il dato
5

il file Albero.cpp: le funzioni pubbliche

Ciascuna funzione del menu richiama una funzione membro, specificando la radice. La sintassi usata dalle funzioni membro consente di realizzare la ricorsione.

il file Albero.cpp: le voci del menu


il file Albero.cpp: la funzione main