Da WIKI CoderDojo Firenze.

Tutorial C++ con le librerie Qt

Finalità di questo tutorial

Questo tutorial è stato pensato per i giovani coders che frequentano il Coder Dojo di Firenze e non vuole essere un’introduzione esaustiva al C++ e tanto meno a Qt. L’impianto didattico dei Coder Dojo è basato sulla libera iniziativa di chi vi accede a apprendere ciò che vuole con il percorso che preferisce, pertanto lo scopo di questo tutorial è solo di fornire una traccia su cui è possibile, con l’ausilio dei mentor, condurre esperimenti nel linguaggio C++ tramite le librerie Qt.

Chiunque sia interessato ad apprendere il C++ in modo autonomo troverà su Internet centinaia di tutorial, anche con video nella propria lingua, molto più accurati e sistematici di questo.

Di cosa stiamo parlando

Che cos’è il C++

Il C++ è un linguaggio di programmazione. Da questo punto di vista non ha nulla che lo distingua dal JavaScript o dal PHP o da mille altri linguaggi che potrebbero essere già stati incontrati negli appuntamenti del Coder Dojo. Ha però una caratteristica che lo distingue in modo netto da quei linguaggi: è un linguaggio compilato.

Linguaggi compilati e linguaggi interpretati

Lavorare con il JavaScript dà una soddisfazione immediata: si scrive il codice, si salva, si ricarica il file HTML nel browser e… tutto funziona! Questa è la caratteristica dei linguaggi interpretati. Il C++ purtroppo non offre la stessa facilità d’uso: quando si è finito di scrivere il codice e si è salvato il file… beh, siamo ancora a metà lavoro. Vediamo perché.

Il problema è che il computer ‘capisce’ un solo tipo di linguaggio: il cosiddetto linguaggio macchina. Quando scriviamo del codice in JavaScript, così come in C++, scriviamo qualcosa che il computer non è in grado di ‘capire’; è necessario un passaggio successivo, nel quale quelle righe JavaScript vengono trasformate nel linguaggio che il computer è in grado di ‘capire’, ossia il linguaggio macchina.

Questa trasformazione può avvenire in due maniere:

  1. ci può essere un programma che legge rigo per rigo quello che abbiamo scritto e lo trasforma sul momento in linguaggio macchina;
  2. ci può essere un programma che legge tutto il file che abbiamo scritto e lo trasforma una volta per tutte in un altro elaborato in linguaggio macchina.

Per fare un paragone, è la stessa differenza fra un concerto dal vivo o uno in playback: nel primo caso i suonatori e il cantante interpretano in diretta la canzone, mentre nel secondo, anche se il pubblico ha l’impressione che siano loro a suonare, alle casse viene inviato una compilation di brani registrata in precedenza.

I linguaggi che vengono letti e trasformati in diretta si sono chiamati per decenni linguaggi interpretati, però di recente è invalso l’uso di riferirsi a loro con una orrenda espressione mista italiano-inglese, ossia linguaggi di scripting. Un esempio classico è il JavaScript.

I linguaggi che devono essere trasformati per intero in linguaggio macchina prima di essere passati al computer si chiamano linguaggi compilati. Uno di questi è il C++.

Vediamo alcune differenze fra questi due modi di scrivere codice.

I linguaggi interpretati (o ‘di scripting’) sono molto veloci da testare. Consideriamo l’esempio fatto prima: un programma in JavaScript. Possiamo scrivere una piccola modifica, salvarla e testarla in pochi secondi ricaricando il file HTML con il tasto F5. Questo è possibile perché il browser che stiamo usando funziona da interprete, ossia contiene dentro di sé una funzionalità che, quando incontra del codice JavaScript, lo trasforma in diretta in linguaggio macchina.

Quindi il JavaScript può funzionare perché c’è un interprete (in questo caso il browser, es. Firefox, Chrome, Safari…) che sta in mezzo fra lui e il computer e li aiuta a ‘capirsi’.

La contropartita è che un linguaggio interpretato può funzionare solo se sul computer è installato il relativo interprete.

I linguaggi compilati sono lenti e faticosi da modificare perché ogni singola modifica richiede che tutto il file sia trasformato di nuovo in linguaggio macchina prima di essere testato. Il programma che trasforma il file in linguaggio macchina si chiama compilatore. Il vantaggio è che una volta compilato, ossia trasformato in linguaggio macchina, funzionerà con molta efficienza senza bisogno di intermediari fra lui e il computer.

Cosa ci serve

Uff! Abbiamo già dovuto spiegare un sacco di cose, non è vero? Coraggio, è quasi finita!


Pulsanti ed eventi: come farne a meno?

Carino il JavaScript, non è vero? Con poche righe si fanno comparire scritte, si cambiano i colori degli oggetti e si modificano le immagini. Il fatto è che il JavaScript è stato pensato per interagire con il linguaggio HTML e ne può sfruttare tutte le potenzialità grafiche. Pensate ad esempio a quanto è semplice disegnare un pulsante.

Il C++, poverino, non ha nessuno che l’aiuti e deve fare tutto da solo; anzi, è il programmatore in C++ che dovrà fare tutto ‘da solo’. Guardiamo un esempio per capirci.

Se si copia il testo sottostante in un file di testo e lo si salva con estensione HTML ci troveremo con un piccolo esempio JavaScript + HTML5 funzionante.

<!DOCTYPE html>

<html lang="it-IT">

<head>
  <meta charset="utf-8">

  <title>JavaScript e HTML5 - un pulsante che non fa quasi niente</title>

  <script type="text/javascript">
    function cambioTesto(){
      document.getElementById("testoDaCambiare").innerHTML = "Ecco! Hai visto? Sono cambiato :-)";
    }
  </script>

  </head>

<body>

  <div>
    <label for="cambiaTesto">Pulsante che modificherà il testo sottostante --></label>
    <input type="button" id="cambiaTesto" value="Premimi per cambiare il testo"
            onclick="cambioTesto();" />
  </div>

  <div>
      <p>Il testo contenuto in questo paragrafo cambierà quando sarà premuto il pulsante soprastante.</p>
  </div>

</body>

</html>

Esaminiamo il codice soprastante. Chi è già venuto al Coder Dojo avrà già riconosciuto tutti i passaggi, ma mi sembra giusto spenderci una parola lo stesso.

Una parte delle righe riguarda codice ‘obbligatorio’, ossia raccomandato del W3C, che però non riveste alcun interesse per noi in questo momento; leviamocelo di torno in due parole.


Codice
Spiegazioni
<!DOCTYPE html> dichiaro che userò la versione HTML nota come HTML5.
<html lang="it-IT"> inizio del codice HTML e dichiarazione che userò la lingua italiana.
<head> inizio delle istruzioni per il browser, ossia quelle che non riguardano ciò che il browser deve mostrare a chi legge la pagina web, ma quelle che deve sapere per poterla mostrare nella maniera corretta.
<meta charset="utf-8"> dichiaro che userò la codifica caratteri UTF-8. L’argomento non è difficile, ma lunghissimo e qui non c’è spazio per affrontarlo. Basti sapere che è caldissimamente raccomandato di scrivere questo rigo, e di scriverlo in questo punto!, se si dichiara che si userà HTML5. Nei file HTML che non sono scritti in HTML5 di solito si legge la stessa cosa in un’altra forma: <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<title>JavaScript e HTML5 - un pulsante che non fa quasi niente</title> la scritta che comparirà sulla finestra del browser.
<!-- … -->
questi sono commenti che servono a rendere più chiaro il codice a chi lo legge e non hanno alcun riflesso sulla pagina web.
<script type="text/javascript"> inizio del codice Javascipt. Questo lo guardiamo tutto insieme dopo.
</script> fine del codice Javascript (vedi rigo precedente).
</head> fine delle istruzioni per il browser (vedi qualche rigo sopra).
<body> inizio della parte che viene mostrata a chi visita la pagina web.
<div> serve a creare un blocco ordinato di righe e a distinguerle da quelle contenute in una altro blocco
<label for="cambiaTesto">Pulsante che modificherà il testo sottostante --></label> Questa fa comparire la scritta “Pulsante che modificherà; il testo sottostante”.
<input type="button" id="cambiaTesto" value="Premimi per cambiare il testo" onclick="cambioTesto();" />
questa fa comparire il pulsante e definisce anche delle istruzioni su quello che il pulsante deve fare. Esamineremo questa istruzione insieme al blocco Javascript poco sotto.
</div> fine del blocco ordinato di istruzioni.
<p>Il testo contenuto in questo paragrafo cambierà quando sarà premuto il pulsante soprastante.</p> Questa fa comparire la scritta “Il testo contenuto in questo paragrafo cambierà quando sarà premuto il pulsante soprastante.”
</body> fine della parte che viene mostrata a chi visita la pagina web.
</html> fine del codice HTML.

In pratica a noi interessano le seguenti righe:

Quella che inizia con <p> e finisce con </p>.

Questo è un paragrafo (<p>), ossia un blocco di testo. Per lo HTML si tratta solo di testo da rappresentare a schermo. La parte interessante è la scritta id="testoDaCambiare". Questa scritta dà l’equivalente di un codice fiscale al nostro paragrafo, ossia un codice che deve essere univoco in tutto il file. Ciò vuol dire che, se scrivessimo del codice che cerca la scritta id="testoDaCambiare", ne troverebbe soltanto una.

Quella che inizia con <input e finisce con />

Questa è la riga che fa comparire il pulsante e merita uno sguardo più approfondito. <input> è un’istruzione che può far comparire oggetti diversi sullo schermo, ma la scritta type="button" specifica che vogliamo un oggetto a forma di pulsante su cui fare click.

Tanto per intenderci, scrivere

  <input type="button" />

è sufficiente per far comparire un pulsante sullo schermo e anche per farlo ‘funzionare’ come un pulsante, cioè per dargli l’effetto ‘premuto’ quando ci si fa click sopra. Provare per credere.

id l’abbiamo già visto per <p>, mentre la scritta value="Premimi per cambiare il testo" è quella che fa comparire la relativa scritta sul pulsante, che altrimenti risulterebbe vuoto.

La parte più interessante è l’istruzione onclick="cambioTesto();". Questa istruzione crea una connessione, un collegamento fra il codice JavaScript e il codice HTML. In pratica grazie a questa scritta noi possiamo fare click su un pulsante HTML e ‘chiamare’ con questo semplice gesto un codice JavaScript. Il codice chiamato sarà quello che segue la scritta function cambioTesto(). Carina l’idea, non è vero?

Quindi, se vogliamo del codice JavaScript da eseguire a comando, ci basta fare così:

  1. creiamo un pulsante HTML (<input type="button"… />);
  2. creiamo un codice JavaScript che inizi con la parola function, es: function codiceDaChiamare();
  3. nell’istruzione <input> aggiungiamo una parte “onclick”, es: onclick="codiceDaChiamare()".

Fatto.

La scritta onlick dice al browser: “quando qualcuno fa click su di me, allora esegui il codice JavaScript che ha il nome che è scritto dopo il segno di uguale”. Questa operazione ha un nome: si chiama evento. Un evento è, per dirla semplice, una cosa che ci si aspetta che accada. Se mi aspetto che accada che qualcuno faccia click sul pulsante che ho fatto comparire sullo schermo, allora scrivo del codice che dovrà funzionare quando il pulsante sarà clickato.

Adesso diamo un’occhiata al codice JavaScript, anche se a dire il vero la parte che m’interessava sottolineare, ossia cos’è un evento, l’abbiamo già trattata.

Il codice JavaScript

  function cambioTesto(){
    document.getElementById("testoDaCambiare").innerHTML = "Ecco! Hai visto? Sono cambiato :-)";
  }

Abbiamo visto che cambioTesto() è solo un nome, un’etichetta, un riferimento che mi consente di collegare un pulsante HTML con del codice JavaScript. Se non avessi questo nome, come potrei dire al browser quale codice chiamare?

La parola function serve invece per indicare che tutto quello che sta fra la parentesi graffa aperta seguente { e la corrispondente parentesi graffa chiusa } è i codice a cui si riferisce l’etichetta cambioTesto(). In pratica, il JavaScript mi consente di fare un po’ come lo HTML, ossia di dividere il codice in spezzoni ordinati.

Nello HTML posso scrivere dei paragrafi in un blocco che inizia con
e finisce con
. In questo modo posso tenere in ordine ciò che scrivo, altrimenti corro il rischio di non capirci più niente.

In JavaScript posso (anzi, devo!) spezzare il codice in blocchi che iniziano con { e finiscono }. Volendo, ad alcuni di questi blocchi posso dare un nome, come abbiamo fatto noi scrivendo cambioTesto(), se vogliamo ad es. collegare quel codice a un pulsante HTML.

L’istruzione

  document.getElementById("testoDaCambiare").innerHTML = "Ecco! Hai visto? Sono cambiato :-)";

è quella che si occupa di modificare il testo e ora come ora ci interessa poco. Per farla semplice, getElementById è incaricato di cercare l’elemento HTML che ha l’etichetta “testoDaCambiare”. Una volta trovato, modifica la scritta che c’è contenuta in “Ecco! Hai visto? Sono cambiato :-)”.

Facciamo un paragone con ciò che possiamo ottenere con Scratch.

Mettiamo di scrivere un esempio come il seguente:


File:C++_Qt_01_Scratch_01_Inizio.jpg


I blocchi di codice sono semplicemente:


File:C++_Qt_01_Scratch_01_Inizio_blocco1.jpg


In questo semplice pezzo di codice troviamo ben due esempi di eventi: uno inizia con “quando si clicca su Sprite 1” e l’altro con “quando si preme il tasto spazio” (a dire il vero c’è anche “quando si clicca su bandiera verde”, perciò sarebbero tre).

Non c’è nessuna differenza tra ciò che succede qui e ciò che succede nel nostro esempio in JavaScript: in entrambi si considera la possibilità che l’utente faccia click da qualche parte, in Scratch su un disegno animato (sprite), in JavaScript su un pulsante HTML. L’effetto risultante sarà il medesimo: quando verrà fatto click, sarà eseguito un blocco di codice. In Scratch questo ‘blocco’ si riconosce subito perché è separato dagli altri in modo grafico; in JavaScript si riconosce perché è contenuto fra due parentesi graffe {}.

Vi immaginate di scrivere un programma che non abbia eventi? Ossia dove non ci siano pulsanti da clickare per far capitare delle cose?

Ebbene, state per farlo! La brutta notizia è che nel C++ nudo e crudo non ci sono pulsanti né eventi.

Si scrive Qt, si legge carino

«Agh!» starete per dire. «Come sarebbe a dire che non ci sono eventi? E come si fa, senza?»

Tranquilli, era solo per spaventarvi :-)

Non è possibile affrontare questo argomento con una lunga trattazione teorica senza scrivere un rigo di codice, ma posso dire questo: di per sé non ci sono né pulsanti né eventi né altri oggetti grafici, ma è possibile aggiungerceli. Il problema è che un sacco di puristi vorrebbero che si aggiungessero pulsanti ed eventi solo dopo che si è imparato il C++, e non fin da subito. Infatti per usare pulsanti ed eventi bisogna ricorrere ad una sintassi un po’ particolare, che nei tutorial tradizionali viene introdotta molto più avanti, dopo che si sono fatte digerire lunghissime filippiche sull’aritmetica dei puntatori e sulle funzioni di callback.

Il tentativo del presente tutorial è invece di stimolare molto presto all’uso degli oggetti grafici, sfruttando le competenze già acquisite con il JavaScript. All’inizio, però, ci dovremo accontentare di fare senza, perché un minimo di teoria su quella bestiaccia che è il C++ va fatta.

Ah, dimenticavo: per avere i pulsanti va installato Qt.

Che cos’è Qt? Beh, tecnicamente si definisce una libreria, o meglio un insieme di librerie, ma questo termine non spiega nulla. In pratica si tratta di una enorme quantità di blocchi di codice già pronti e impacchettati, ognuno già dotato del suo nome, o etichetta, come quello che abbiamo usato per il JavaScript. Questi blocchi di codice sono capaci di disegnare i pulsanti sullo schermo e di aggiungerci degli eventi, molto simili all’evento onclick che abbiamo visto prima.

Perciò noi non useremo, con gran rabbia dei puristi, il C++ puro, bensì quella parte del C++ che ci consente di usare le librerie Qt.

Un’ultima cosa: Qt si legge come la parola inglese cute, che vuol dire carino. È voluto.

L’ambiente di programmazione

Per scrivere in JavaScript abbiamo cercato di usare determinati programmi che sono in grado di facilitarci la vita, ad esempio colorando le parole più importanti in modo da visualizzarle meglio. Ad esempio, agli utenti Windows abbiamo chiesto di installare Notepad++.

È il momento di una buona notizia: gli stessi programmi che avete usato per scrivere HTML o JavaScript sono in grado di aiutarvi anche con il C++.

Però c’è una notizia anche migliore: Qt non è solo un’insieme di librerie, ma un vero e proprio ambiente di programmazione integrato dedicato al C++. Questo genere di programmi si chiamano IDE (Integrated Development Environment). Che cosa significa? Beh, significa che non solo vi può colorare le parole, ma è in grado anche di darvi buoni consigli e accorgersi al posto vostro di potenziali errori nel codice che scrivete.

Bello, eh? Ma non è finita qui: Qt può gestire il compilatore al posto vostro. Vi ricordate che cos’è il compilatore? È quel programma che trasforma il vostro codice in linguaggio macchina. Il C++ non può essere interpretato, ossia eseguito subito, ma deve essere compilato prima di essere eseguito. Orbene, i compilatori delle volte possono essere un po’ complicati da usare; invece, con Qt basta fare click sul pulsante esegui e lui si occuperà di tutto al posto vostro: salvataggio dei file, compilazione e esecuzione del programma.

Pensate sia finita qui? Ebbene, no: ci sono altre tre belle cose da dire di Qt:

  1. La versione base è gratis.
  2. Quando si installa Qt, automaticamente si installa anche un compilatore, risparmiandoci un bel po’ di lavoro.
  3. Esiste una versione di Qt per ogni piattaforma: Windows, Linux 32 bit, Linux 64 bit, Mac.

Ciò significa che non abbiamo bisogno di altro che Qt per cominciare a lavorare.

Per quei pochi che ancora non si fossero informati ;-) Qt si trova qui: <a href="http://qt-project.org/">http://qt-project.org/</a>

Ricordatevi che non ci bastano le librerie, vogliamo l’ambiente integrato di sviluppo, ossia Qt Creator.

L’installazione di Qt

L’installazione di Qt di solito non dà problemi; comunque sia è un argomento che esula da questo tutorial. Qui aggiungo solo delle note.

Sul sito sono messe in evidenza le librerie, mentre il link a Qt Creator, che è quello che vogliamo noi, è un po’ meno visibile: oggi come oggi (novembre 2014) per trovare il collegamento per scaricare Qt Creator bisogna scorrere la pagina dei download verso il basso.

Il motivo per cui in primo piano si trovano le librerie è che le librerie Qt si possono usare anche con altri compilatori, ma non è ciò che noi faremo. Inoltre, quando escono aggiornamenti per le librerie, di solito i programmatori sono interessati solo a quelli e non hanno intenzione di re-installare l’intero ambiente integrato da cima a fondo.

Quando si sceglie il file da scaricare, abbiamo due opzioni: possiamo scaricare solo lo installer oppure fin da subito l’intero pacchetto. Lo installer è solo un programmino che ci aiuta ad installare Qt scaricando il necessario dal sito – questa è l’opzione consigliata. Il pacchetto completo, invece, consente di scaricare tutto subito e dopo procedere all’installazione anche senza essere collegati a Internet.

I nomi degli installer somigliano a questi:

  • Per Windows: qt-opensource-windows-x86-1.6.0-5-online.exe
  • Per Linux 32 bit: qt-opensource-linux-x86-1.6.0-5-online.run
  • Per Linux 64 bit: qt-opensource-linux-x64-1.6.0-5-online.run
  • Per Mac: qt-opensource-mac-x64-1.6.0-5-online.dmg

Ripeto: con i file elencati sopra per installare Qt dovete essere collegati a Internet per tutta la fase di installazione.

La versione per Linux è ovviamente disponibile per tantissime distribuzioni tramite i relativi repository, ma può capitare che la versione sui repository non sia aggiornata. È successo a me con Kubuntu. Usare lo installer scaricabile dal sito non pare un’opzione malvagia.

Le prossime puntate di questo tutorial partiranno dal presupposto che si sia riusciti a installare Qt Creator.

Tutorial C++ e Qt: partiamo con calma

Il C++ può rivelarsi un po’ complicato per cui è quasi una tradizione iniziare a parlarne con un programmino molto semplice che non fa quasi nulla. Vedremo però che contiene già un sacco di cose che devono essere ben spiegate per essere capite.

Cominciamo con l’avviare Qt Creator. La mia versione è installata in Kubuntu Linux perciò trovo il comando in Kikoff → Applicazioni → Sviluppo → The IDE of choice for Qt development.


File:Qt_appena_aperto.png


Nella mia versione ci sono un paio di progetti già creati, perciò la vostra schermata iniziale risulterà diversa. Questo non importa perché quella che ci interessa per ora è solo la barra grigia sulla sinistra, quella dove compaiono le scritte Welcome, Edit, Design, Debug, Projects, Analyze e Help. Cerchiamo di inquadrarla fin da subito perché la useremo un sacco di volte.

Se ci si fa caso, adesso è selezionata la casella Welcome. Torneremo su questo fra poco.

Adesso dobbiamo fare una cosa che ci farà risparmiare un sacco di tempo più avanti: dobbiamo decidere dove salveremo i nostri file. Può sembrare una cosa così banale da essere sciocca, ma ora non ho modo di spiegare quanto tornerà utile. È importante che scegliamo una cartella che sia contenuta in un’altra cartella che riguardi comunque Qt o il C++, quindi che non sia figlia diretta di Documents / Documenti.

Una buona idea potrebbe essere di creare prima una cartella con un nome tipo ‘ProgrammiCpp’, e poi dentro di quella un’altra con un nome tipo ‘CppQt’. La scelta dei nomi dipende da voi, ma cercate di rispettare questa logica: create due cartelle, una dentro l’altra. Noi useremo l’ultima, quella che potrebbe chiamarsi ‘CppQt’, ma molto più avanti vedrete, per tenere i file in ordine, che ci farà comodo che sia figlia di un’altra cartella vuota.

D’ora innanzi partirò dal presupposto che i nostri file vengano salvati in

…Documents/ProgrammiCpp/CppQt ma voi chiamate pure le cartelle come volete, non fa nessuna differenza.


Torniamo ora a Qt perché è il momento di iniziare a programmare.

Qt Creator è pensato per aiutarci a scrivere in C++, ma perché possa esserci utile dobbiamo spiegargli cosa vogliamo fare.

Allora: in Qt Creator ogni programma che vogliamo scrivere ha bisogno del suo progetto. Per ora ci basta sapere che un progetto in Qt Creator è un contenitore per i file del nostro programma. Per cominciare a programmare in Qt bisogna quindi creare un progetto e dargli un nome.

Cominciamo quindi a fare click su File → New File or Project (la mia versione è in inglese, ma voi potreste avere la stessa voce in italiano).

Si aprirà una finestra per la creazione dei progetti:


File:Qt_nuovo_progetto.png


In questa finestra Qt si offre di aiutarci a creare un progetto con tutte le facilitazioni della sua vasta libreria. Noi però siamo masochisti e decliniamo l’offerta, giacché desideriamo iniziare con il C++ standard, quello senza le librerie Qt.

Nella casella di sinistra dobbiamo quindi optare per un malinconico Non-Qt Project. Come si noterà, le scelte disponibili nella colonna centrale cambiano. Adesso è comparsa la scelta che piace a noi: Plain C++ Project. Il nome in italiano potrebbe essere diverso, ma l’immagine seguente dovrebbe aiutare a districarsi:


File:Qt_Plain_C++_Project.png


Facciamo click su Choose…

Si apre una nuova finestra dove ci viene chiesto come vogliamo chiamare il progetto e dove vogliamo salvarlo. Il nostro primo programma è il classico Hello Word!, ossia un programma che fa comparire a schermo la scritta “Ciao, mondo!” e basta; perciò possiamo chiamarlo ‘Saluto’. La cartella dove salvarlo sarà quella decisa prima.


File:Qt_Saluto.png


Nelle due schermate successive non modifichiamo nulla e arriviamo al pulsante Finish, premuto il quale, dopo qualche secondo, si aprirà una schermata del tutto diversa. Prima di parlare di questa nuova schermata, però, mi piacerebbe che andaste a controllare che cosa è successo nella cartella in cui avete deciso di salvare il progetto.

Come vedete è comparsa una nuova cartella, Saluto. Bene, i nostri file relativi a questo progetto dovranno essere salvati tutti in quella cartella.

Con questa osservazione è ora di farla finita con Qt e di parlare finalmente del C++.


Ciao, mondo!

Qt si è trasformato: mentre prima era selezionata la casella Welcome, adesso è selezionata la casella Edit. Tutte le volte che apriremo un progetto (oppure ne creeremo uno nuovo) Qt ci darà la possibilità di modificarlo subito ponendosi in ‘modalità’ Edit. Se facciamo click su Welcome ci troveremo nella schermata con cui abbiamo iniziato, ma tornando a clickare su Edit potremo di nuovo fronteggiare il progetto appena creato.

Vediamo un po’ cosa ci troviamo davanti. Dovrebbe essere una schermata su per giù come questa:


File:Qt_CiaoMondo.png


Beh, qui ci aspetta un’amara sorpresa: Qt Creator, senza nemmeno chiedercelo, ha già scritto tutto il codice al posto nostro!

Un po’ troppo efficiente, vero? Beh, non è il caso di prendersela: come dicevo è già da alcuni decenni che è consuetudine iniziare tutti i manuali e i tutorial sul C++ con il programma ‘Ciao, mondo!’, perciò si tratta del codice più conosciuto dai programmatori in C++. Partendo dal presupposto che l’utente possa usare Qt per la prima volta, questo, quando crea un nuovo progetto, ci inserisce fin da subito il codice che è sicuro che il programmatore conosca; in questo modo l’utente si trova subito a suo agio.

Adesso, però, visto che non solo è la prima volta che usiamo Qt Creator, ma anche la prima volta che scriviamo codice C++, vediamo di capire come è fatto questo programma.

Sulla destra della barra su cui compaiono le diciture Welcome, Edit, ecc., c’è una colonna bianca in cui si possono riconoscere le icone di una cartella e di alcuni files, con i rispettivi nomi. Proviamo a guardare cosa c’è dentro la cartella Saluto sul nostro hard disk… Sorpresa! Sono gli stessi nomi di file. A questo punto sappiamo a cosa serve questa colonna: è l’elenco dei file che compongono il nostro progetto.

Nella colonna di destra compaiono invece delle scritte che al momento paiono incomprensibili. Bene, quello è il codice C++ che compone il programma ‘Ciao, mondo!’. Se diamo un’occhiata alle due colonne insieme, ci rendiamo conto che il codice che vediamo nella colonna di destra è quello contenuto nel file main.cpp elencato a sinistra.

Bene: se stessimo scrivendo il codice C++ senza appoggiarci a un ambiente integrato di sviluppo, ci basterebbe aprire un editor di testo qualsiasi e scrivere le righe che appaiono nella colonna di destra, salvare con il nome mail.cpp e compilare. Il nostro programma sarebbe già pronto a funzionare.

Un ambiente integrato di sviluppo, come è invece Qt, ha bisogno invece anche di altri file per tenere traccia di ciò che sta facendo: ecco il motivo per cui ci sono altri file oltre a main.cpp. A noi però interessa solo il codice C++, perciò non staremo neanche a prenderci cura di ciò che è scritto negli altri file.

Intanto vediamo se il codice è corretto e funziona oppure se Qt ci ha fregato. Compiliamo subito questo programma e mandiamolo in esecuzione.

Per compiere questa operazione fuori di un ambiente integrato di sviluppo dovremmo saper dare istruzioni piuttosto complicate, invece in Qt Creator ci basta fare click sulla barra grigia a sinistra, che ormai dovremmo saper inquadrare subito, in particolare sulla terza icona dal basso, quella a forma di una freccia verde che indica a destra.


File:Qt_CiaoMondo_Esegui.png


Il risultato può essere graficamente diverso a seconda di quale versione di Qt stiamo usando, se per Linux, Mac o Windows, ma a tutti si dovrebbe aprire, dopo qualche secondo, una finestrella in cui compare la scritta “Hello Word!” o simili. A me viene così:


File:Qt_CiaoMondo_ris_1.png


Beh, anche se può apparire un po’ poco, intanto possiamo dire che Qt non ci ha traditi e il codice che ha scritto funziona. Inoltre adesso sappiamo come compilare e mandare in esecuzione un programma in un solo click.


Ehi, avevamo detto “Ciao, mondo!”

È vero! Chi aveva mai parlato di “Hello Word!”? E poi senza virgola a separare il vocativo… Non ci siamo proprio. Dobbiamo mettere subito mano a questo programma.

Intanto, come da istruzioni, chiudiamo la finestrella che si è aperta (ricordiamoci di farlo sempre!).

Poi andiamo nel nostro codice e troviamo la seguente riga:

  cout << "Hello World!" << endl;

Indovinate un po’ a cosa serve? Mi sembra già chiaro, ma lo sarà ancora di più quando avremo sostituito le parola Hello Word con Ciao, mondo, di modo che la riga venga così:

  cout << "Ciao, mondo!" << endl;

A questo punto facciamo di nuovo click sull’icona a forma di triangolo verde e vediamo il risultato.

Qt dovrebbe salvare il file modificato –oppure chiederci se vogliamo salvarlo–, compilarlo e mandarlo in esecuzione. Nel caso cominciassero ad apparire strane scritte sulla parte bassa della finestra, invece, vorrebbe dire che abbiamo sbagliato qualcosa, per esempio dimenticandoci una delle due virgolette.

Bene, chiudiamo anche la nuova finestra che si è aperta e diamo un’occhiata al nostro programma.

#include <iostream>

using namespace std;

int main()

{

   cout << "Ciao, mondo!" << endl;
   return 0;

}

Vi ricorda nulla la scritta main()? Non vi viene in mente il nostro programma precedente in JavaScript, dove abbiamo scritto function cambioTesto()? Non vi sembra che abbiano qualcosa in comune?

Esatto, è proprio così: in entrambi i casi c’è un nome seguito da una parentesi aperta e una chiusa:

nome()

Bene, per il C++ funziona proprio come per il JavaScript: quando c’è un nome seguito da parentesi tonda, vuol dire che quello è un nome di funzione. La cosa non dovrebbe sorprenderci, visto che entrambi sono stati sviluppati partendo dal linguaggio C e che anche per il linguaggio C le cose stanno in questa maniera!

Ma vi ricordate cos’è una funzione? Diciamolo in modo semplice:

Una funzione è un blocco di codice che inizia con una parentesi graffa aperta { e finisce con una parentesi graffa chiusa }.

Le funzioni di solito hanno un nome, ossia un’etichetta che li contraddistingue e che consente di chiamarle da altre parti del codice, o addirittura, nel caso del JavaScript, da eventi HTML. Può capitare che ci siano funzioni senza nome, che nel JavaScript si chiamano funzioni anonime e nel C++ funzioni lambda, ma noi non ne scriveremo perché troveremo il modo di evitarle.

Confrontiamo i due blocchi di codice:


JavaScript
C++
function cambioTesto(){ int main() {

Le uniche differenze che ci vedo io sono:

  1. la scritta function nel JavaScript (che non c’è nel C++);
  2. la scritta int nel C++ (che non c’è nel JavaScript).

Qualcuno potrebbe obiettare che c’è anche un’altra differenza: il ritorno a capo dopo la parentesi tonda chiusa nel codice C++, ma in realtà quello è solo una questione di gusti. Nessuno mi può impedire di scrivere

int main() {
   cout << "Ciao, mondo!" << endl;

se mi va, e infatti il codice funzionerebbe benissimo lo stesso; provare per credere. Quella di mandare a capo la parentesi graffa quando si inizia a scrivere una funzione è solo un’abitudine, ma il compilatore non ci fa caso e trasforma il codice in linguaggio macchina esattamente allo stesso modo.

Diamo un’occhiata alle altre due differenze.

Come prima cosa possiamo notare che nel C++ non è necessario usare la parola function per dichiarare che si sta scrivendo una funzione: basta che ci sia la sequenza nome+parentesi tonde.

Il C++ è invece un po’ pignolo in una cosa di cui il JavaScript non si cura molto: la cosiddetta tipizzazione. Brrr! Che parola brutta. Io l’ho sempre odiata. In questo momento non riuscirei a spiegarla, ma è un argomento importante e lo tratteremo presto. Per ora ci basti sapere che la parola int ha qualcosa a che fare con questo problema della tipizzazione, ma dobbiamo scrivere un’altra funzione per capire bene cosa significhi.

Una domanda che potrebbe venire spontanea a qualcuno potrebbe essere: ma come si è permesso Qt di scegliere il nome della funzione al posto mio? Perché ‘main’, tra l’altro? Se ho scelto di chiamare la funzione JavaScript “cambioTesto”, questa non potevo chiamarla ciaoMondo?

int ciaoMondo()

Beh, purtroppo no. Per capire la risposta torniamo un attimo al programma JavaScript e ricordiamoci come funziona. In realtà il codice JavaScript non esegue fin da subito, ma solo dopo che si è fatto click sul pulsante Premimi per cambiare il testo. Però, se rileggiamo il codice, ci accorgiamo che il codice JavaScript è scritto molte righe sopra l’istruzione <input type=”button”… Se ci riflettete, questo vuol dire che il browser legge il codice JavaScript, ma lo ignora finché non riceve il comando di eseguirlo.

In realtà siamo abituati a considerare <body> come il punto di inizio del codice da ‘eseguire’, ossia quello che dà un risultato su schermo; di solito non facciamo molto caso a quello che compare prima, anche se il Browser lo legge tutto.

Lo stesso principio vale per il C++: il codice da ‘eseguire’ è quello che comincia con main.

Immaginiamo di andare a vedere una partita di un qualche sport, pallavolo, pallacanestro, calcio… Sul campo ci sono un sacco di giocatori che si passano la palla, corrono, saltano… Ma la partita non è ancora iniziata. D’un tratto si ode il fischio dell’arbitro e tutti si fermano e vanno a prendere posizione: quello è l’inizio della partita, prima era il riscaldamento.

Nel C++ possiamo immaginare qualcosa di simile: qualunque cosa sia scritta prima, main è il fischio dell’arbitro. Perciò main non può mancare mai. Nel nostro caso, essendoci una sola funzione, beh, non può che chiamarsi main.

Adesso che abbiamo rotto il ghiaccio con le funzioni, che sono un argomento bello tosto, diamo un’occhiata la resto, così possiamo cominciare a modificarlo.

Blocchi dappertutto

Il C++ è un linguaggio molto organizzato: tutto il codice che scrivete deve entrare in un ‘blocco’. Per ora abbiamo visto solo i blocchi di codice che possono avere un nome e sono chiamati funzioni, ma ce ne sono anche altri. Si riconoscono perché iniziano e finiscono con le parentesi graffe, ma ce ne occuperemo via via che li troveremo.

L’utilità di scrivere tutto a blocchi e di dargli un nome quando possibile consiste nel fatto che si possono riutilizzare. Date un’occhiata alla parola cout, ad esempio.

  cout << "Ciao, mondo!" << endl;

Cout in realtà è un blocco di codice di cui non dovete per forza sapere qualcosa. Ossia, non dovete per forza andare a leggere il codice di cui è composto per sapere cosa fa. Il suo compito è facilmente reperibile su un qualsiasi manuale del C++ e adesso ve lo posso semplificare in due parole: cout riceve le scritte che gli vengono inviate tramite l’operatore “<<” e le invia allo schermo.

Ossia, se volete comunicare qualcosa a chi sta usando il programma e decidete di comunicarlo facendolo comparire a schermo, vi basta scrivere:

  cout << "Ehi, utente di questo programma, ti volevo dire che...";

L’uso di cout è quindi piuttosto semplice, ma se ci domandassimo come fa a farlo, allora dovremmo andare a leggerci tutte le decine e decine di righe di codice di cui è composto il blocco che ha nome cout. Adesso stiamo leggendo le righe di cui è composto il blocco di codice che ha nome main, ma per fortuna sono solo 2 e semplici. Con cout vi assicuro che avremmo da parlarne per settimane! Ma non ci servirebbe a nulla, se non a imparare: per usare cout ci basta sapere cosa fa, e non come fa a farlo.

Lo stesso vale per la parola endl. endl significa solo “torna a capo”, che è quello che fa il tasto INVIO quando stiamo scrivendo del testo normale. Se non usiamo endl, cout non può sapere che vogliamo tornare a capo e continua a scrivere sulla stessa riga.

Esempio. Modifichiamo il nostro programma così (ricordiamoci che la finestrella comparsa prima, quella in cui ci veniva mostrato il funzionamento del nostro programma, deve essere stata chiusa!):

#include <iostream>

using namespace std;

int main()
{
   cout << "Ciao, mondo!";
   cout << "Sono a fare un po' di esperimenti con il C++";

   return 0;
}

E mandiamolo in esecuzione facendo click sulla freccia verde – anzi, chi vuole può sperimentare un altro metodo: CTRL + R.

Ricordatevi che, se non avete salvato, Qt prima di compilare vi chiede se volete salvare.

A me compare la seguente finestra:

File:Qt_CiaoMondo_ris_2.png

Che ve ne pare? Lo riconoscete il codice che abbiamo scritto? Beh, c’è tutto, solo che è tutto appiccicato in un’unica riga. Questo è perché non abbiamo mai detto a cout di tornare a capo. Proviamo invece a dirglielo:

#include <iostream>

using namespace std;

int main()
{
   cout << "Ciao, mondo!" << endl;
   cout << "Sono a fare un po' di esperimenti con il C++" << endl << endl;

   return 0;
}

Il risultato è molto più leggibile:

File:Qt_CiaoMondo_ris_3.png


L’esempio mi sembra non richieda spiegazioni, però servono due note:

  • cout si pronuncia in inglese come se fosse scritto c-out, quindi in italiano suona all’incirca si-aut.
  • endl è la fusione delle parole inglesi end e line, perciò non c’è nulla di male a pronunciarlo endline – ‘endlain’.

La cosa importante da capire è che possiamo scrivere un blocco di codice con un nome in un punto e usarlo in un altro dando in pasto al compilatore solo il nome, un po’ come nel programma in JavaScript abbiamo scritto onclick="cambioTesto();" per richiamare il blocco di codice che portava il nome cambioTesto. Pensateci un po’: se la funzione cambioTesto fosse stata scritta da qualcun altro e magari si fosse trovata mischiata fra centinaia di altre, tanto che non fossimo riusciti a ritrovarla leggendo il codice, avremmo potuto usarla lo stesso?

Certo che sì! Non è nostro compito sapere dove si trova, e nemmeno cosa c’è scritto dentro, ma solo come si chiama e cosa fa. Al resto pensa il computer.

Adesso conosciamo cout e endl, nel senso che sappiamo il loro nome e cosa fanno, quindi possiamo usarli dove vogliamo. Ma dove si trovano i blocchi di codice che sono richiamati dai loro nomi? Come fa il compilatore a trovarli?

Semplice: glielo abbiamo detto noi :-)

Sorpresi? Il trucco è semplice: la prima riga del nostro programma recita:

#include <iostream>

iostream è il nome di un file e in quel file è contenuto il codice che porta il nome cout e il codice che porta il nome endl.

Il significato di questa istruzione è: caro compilatore, prima di leggere il resto del mio codice, vai a cercare il file iostream e copia-incolla il suo contenuto in questo punto.

Questa operazione viene compiuta tutte le volte che facciamo click sulla freccia verde. In questo modo tutto il codice che è contenuto in quel file, centinaia e centinaia di righe di codice già pronte da usare, tutte impacchettate in blocchi con il loro bravo nome sopra, vengono aggiunte alle righe che abbiamo scritto noi, aumentando in modo incredibile le funzionalità che possiamo inserire nel nostro programma.

E non è finita qui: di quei file pieni di blocchi di codice già pronti (si chiamano librerie) ce ne sono moltissimi disponibili gratuitamente. Oltre a quelli che ci fornisce Qt, che sono una quantità enorme.

A questo punto abbiamo visto quasi tutto, il resto è molto astratto e ne faremo solo un accenno, per ora:

Codice
Cosa fa il compilatore
#include <iostream> copia-incolla il contenuto del file iostream al posto di questo rigo
using namespace std; se nel programma trovi alcune parole che sono uguali ai nomi dei blocchi di codice contenuti in iostream (ad es. cout o endl), parti dal presupposto che l’utente voglia usare quei blocchi di codice
int main() { definisco una funzione che si chiama main. main è obbligatoria in un programma C++
cout… già visto
return 0; questo lo vediamo tra poco
} fine della funzione main. Quando si esce da main il programma finisce.

Tutorial C++ e Qt: la nostra prima funzione

Quanta teoria, non è vero? Il C++ è un po’ così, bisogna procedere con calma. E poi stiamo anche imparando a usare Qt nel frattempo, che ci prende il suo tempo. Ma andiamo avanti.

Immaginiamo di voler scrivere l’equivalente C++ del seguente programma Scratch:


File:C++_Qt_01_Scratch_02.png


Immaginiamocelo prima in JavaScript.

<!DOCTYPE html>

<html lang="it-IT">
<head>
  <meta charset="utf-8">

  <title>JavaScript e HTML5 - un pulsante che saluta</title>

  <script type="text/javascript">
    function cambioTesto(){
      var utente = document.getElementById("risposta").value;
      document.getElementById("testoDaCambiare").innerHTML = "Ciao, " + utente + "!";
    }
  </script>
</head>

<body>
  <div>
    <label for="risposta">Qual è il tuo nome?</label>
    <input type="text" id="risposta" />
  </div>
  <div>
    <label for="cambiaTesto">Pulsante che modificherà il testo sottostante --></label>
    <input type="button" id="cambiaTesto" value="Premimi per cambiare il testo"
                onclick="cambioTesto();" />
  </div>
  <div>
    <p>Il testo contenuto in questo paragrafo cambierà quando sarà premuto il pulsante soprastante.</p>
  </div>
</body>
</html>

Il programma è molto simile al precedente e credo che da spiegare ci sia solo la piccola modifica alla funzione cambioTesto(). In modo molto schematico:

var utente → questa istruzione definisce una variabile. Che cos’è una variabile? Questo è molto importante perché le troveremo anche nel C++, solo che lì saranno un po’ più complicate perché si divideranno in variabili ‘normali’, puntatori e references.

Immaginate di stare scrivendo al computer sotto dettatura. A un certo punto chi vi detta si dimostra un po’ insicuro e vi chiede: «Senti, non sono molto sicuro di volerlo scrivere così. Fammi un favore, metti da parte l’ultimo paragrafo e dopo lo riguardiamo con calma.» A quel punto fate una copia dell’ultimo paragrafo e la salvate in un file a parte, a cui date un nome, tipo Paragrafo da riguardare o simili. È necessario che vi ricordiate cosa c’è scritto in quel paragrafo? No. Ormai l’avete salvato. Quando volete sapere cosa contiene, vi basta chiedere al computer di mostrarvi il contenuto del file che ha il nome Paragrafo da riguardare. Bene, una variabile è una cosa molto simile. Una variabile è uno spazio di memoria a cui date un nome. In quello spazio di memoria potete dire al computer di salvare tutti i dati che a voi interessano. Non è necessario che vi ricordiate quali dati sono: quando vi servono, vi basta dire al computer di farvi vedere i dati contenuti nella cella di memoria che ha il nome che avete scelto (beh, certo, il nome che avete assegnato alla cella di memoria ve lo dovete ricordare…). Questa istruzione dice al computer: «Ehi, ciccio, metti da parte una cella di memoria e dalle il nome “utente”. Dentro ci metterai i dati che ti dico io e, quando te li richiederò, tu me li porterai.»


document.getElementById("risposta").value → Questa parte dice: «Caro computer, trova l’elemento HTML che ha id=”risposta”. Leggi il valore che è contenuto nella casella di testo (ossia, il testo immesso dall’utente).»


var utente = document.getElementById("risposta").value;

A questo punto la riga intera dovrebbe essere chiara: prendo il testo contenuto nell’elemento HTML con id = “risposta” e lo inserisco nella cella di memoria cui ho dato il nome “utente”.


document.getElementById("testoDaCambiare").innerHTML = "Ciao, " + nome + "!";

Questa riga non è cambiata molto rispetto a prima e mi sembra abbastanza chiara. Il contenuto dell’elemento HTML con id = “testoDaCambiare” deve diventare la concatenazione di questi tre valori: la parola Ciao, il valore che è contenuto nella cella di memoria denominata ‘utente’ e il punto esclamativo.


NOTA: non so se ve lo ricordavate, ma in JavaScript tutte le istruzioni devono finire con il punto e virgola. Orbene: la stessa regola vale anche per il C++ (nonché, indovinate un po’, per il padre di entrambi, il C).


O scriviamolo in C++, perdindirindina

Ecco come viene il programma in C++:

#include <iostream>

using namespace std;

int main()
{
   string utente;

   cout << "Qual è il tuo nome? ";

   cin >> utente;

   cout << "Ciao, " << utente << "!" << endl << endl;

   return 0;
}

Quando fate click sulla freccia verde, oppure premete CTRL + R, nella finestrella che si apre comparirà la scritta: “Qual è il tuo nome?”. Dopo che avrete scritto una risposta, ad esempio “Anacleto” e avete premuto INVIO, il programma risponde con “Ciao, Anacleto!”, dopodiché finisce.

Diciamo subito che il programma ha un difetto. Se rispondete “Anacleto Teobaldo Fumagalli de’ Chiacchiararelli”, il programma comunque saluta così: “Ciao, Anacleto!”. Il motivo per cui succede è che ci sono diversi modi di accettare l’input dell’utente e noi abbiamo scelto il più semplice, che si fa un po’ ingannare dagli spazi. Ma non staremo qui a fare una carrellata dei diversi modi che offre il C++ standard di accettare testo dall’utente perché il nostro obiettivo è arrivare a usare le librerie Qt, che offrono soluzioni molto più robuste a questo problema.


string utente;

Vediamo come funziona il programma. Saltiamo ciò cui abbiamo già dato un’occhiata e entriamo subito in main. la prima istruzione nuova è string utente; Bene, questo comando è assolutamente identico a var utente che abbiamo visto per il JavaScript. La differenza, e qui è giunto il momento di soffermarci sul punto, è nella tipizzazione.

Il JavaScript non fa molte domande quando si tratta di lasciare blocchi di memoria a disposizione dell’utente perché li usi come variabili, ossia dando loro un nome. In pratica al JavaScript basta dire: «Ehi, JavaScript, metti da parte lo spazio per una variabile. Chiamala ‘utente’.» E JavaScript obbedisce.

Il C++ è decisamente più rompiscatole; infatti vuole sapere per quale tipo di dati deve lasciare spazio di memoria. Sembra una cosa molto complicata, ma… lo è! :-) Per fortuna, rispetto al C, il C++ ha introdotto molte facilitazioni, e Qt ne aggiunge altre che potrebbero quasi farci dimenticare del problema – però noi vogliamo imparare anche un po’ di C++ standard e perciò cerchiamo di capire dove stia il problema. Dunque, nel JavaScript, come si è detto, una volta che avete dichiarato la vostra variabile ci potete mettere dentro tutto ciò che volete. Nel C++ no, non è così. Nel C++ quando dichiarate una variabile dovete scegliere che cosa ci deve entrare: se dichiarate che ci devono entrare numeri, allora non ci potete mettere testo; se invece dichiarate che si tratta di una variabile per il testo, allora non ci potete mettere numeri. Dovete scegliere prima. La scelta si compie facendo precedere il nome della variabile da una parolina che specifica il tipo di dati che saranno autorizzati a entrarci. Facciamo degli esempi. La parolina int specifica che nella variabile che sto per dichiarare potranno entrare solo numeri dell’insieme degli Interi. Per chi non lo avesse ancora studiato a scuola, vuol dire numeri tipo 1, 2, 5, 1876, -4, - 536, 0, ecc. ecc. Ossia numeri positivi o negativi che però non abbiano una parte decimale, ossia una virgola e delle cifre dopo. Quindi, se scrivo:

   int numeriinteri;

sto dichiarando una variabile, il cui nome sarà numeriinteri, che potrà contenere solo numeri interi. Il nome, ovviamente, non ha nessuna influenza sul contenuto della variabile. Cioè, se dichiaro una variabile così:

   int quiCiMettoDelTesto;

non importa se il nome che ho scelto ‘inganna’: lì dentro il compilatore mi farà mettere solo numeri interi (è chiaro che in realtà conviene sempre scegliere dei nomi che siano coerenti con ciò che stiamo facendo, sennò ci complichiamo la vita da soli).

Quindi l’istruzione:

   quiCiMettoDelTesto = 6;

andrà a buon fine, mentre l’istruzione:

   quiCiMettoDelTesto = "Mario";

sarà bloccata dal compilatore.

Se vi domandate cosa succede quando si scrive qualcosa su cui il compilatore non è… d’accordo, la risposta è: provate! :-) Quel che succede è che il compilatore si arrabbia di brutto e vi risponde con una sfilza di messaggi di errore che sembrano una dichiarazione di guerra – oltre a questo, si blocca e non vi compila il programma. Questo però, ossia la ‘decifrazione’ dei messaggi di errore del compilatore è un argomento troppo complicato da trattare qui.

Avete indovinato cosa significa quindi “string utente;”? Per chi avesse dei dubbi, significa: «Caro compilatore stizzoso, lasciami lo spazio in memoria per una variabile, cui darò nome ‘utente’, sapendo che ci metterò dentro del testo!». Quindi string sta per ‘stringa di testo’, cioè insieme di parole, di caratteri.

Indovinate un po? Anche string è una parolina magica che rappresenta un blocco di codice. E sapete dove si trova il blocco di codice chiamato string? Avete notato altre dichiarazioni #include nel nostro codice? Beh, questo già fornisce la risposta ;-) Il blocco di codice string è definito nel file iostream. Meglio precisare subito: è definito anche in iostream. A dir la verità, se vogliamo usare tutte le potenzialità di una variabile di tipo string, dobbiamo includere un file specifico che contiene il codice completo (dentro iostream ci sono solo le parti per le operazioni più comuni). La dichiarazione, che però ora non ci serve, sarebbe:

#include <string>

cout << "Qual è il tuo nome? "; Dai! Questa è chiara, ormai, no? Voglio solo rilevare l’assenza della parola endl, affinché che i caratteri digitati dall’utente compaiano sulla stessa linea della domanda e non il rigo sotto.


cin >> utente;

Altra cosa che mi sembra non meriti lunghe spiegazioni. cin è un altro blocco di codice definito in iostream che somiglia molto a cout (e infatti si legge c-in, ossia in modo simile all’italiano si-in). Cosa fa questo blocco di codice? cin prende i caratteri digitati sulla tastiera e li rovescia in una variabile, ossia quella che è scritta dopo il simbolo ‘>>’. Quindi cin >> utente; significa solo: «Guarda cosa succede sulla tastiera e, quando l’utente preme INVIO, ricopia tutto quello che hai visto nella variabile ‘utente’, che è stata dichiarata stringi e quindi è idonea allo scopo.» Come abbiamo visto, cin ha un modo di gestire gli spazi che può non essere quello che l’utente si aspetta, ma… diamine, siamo al nostro primo programma!


cout << "Ciao, " << utente << "!" << endl << endl;

Spero non sembri difficile. L’istruzione dice: «Caro computer, adesso scrivi a schermo (cout): la parola Ciao, poi il contenuto della variabile ‘utente’, e poi un punto esclamativo; e poi torna a capo due volte.»


Sì, ma senza funzioni non funziona!

Abbiamo detto che tutto il codice C++ deve stare all’interno di un blocco, ossia all’interno di parentesi graffe {}. A dire il vero non sono stato molto preciso: diciamo che il 99% e più deve stare all’interno di un blocco, ma ci sono piccole eccezioni. Ne abbiamo già viste un paio:

#include <iostream>
using namespace std;

Queste due istruzioni non sono all’interno di nessun blocco.

Per capire la differenza, adesso sposteremo un po’ le righe che abbiamo scritto in modo da creare altri due blocchi, che saranno due blocchi con un nome, nello specifico due funzioni. Non ce ne sarebbe bisogno, in un programma così piccolo, ma noi lo facciamo solo per imparare un po’ di C++.

Cerchiamo prima di capire se possiamo dare una regola generale su quali siano le istruzioni che sono ‘autorizzate’ a stare fuori dai blocchi. Per capirlo, torniamo un attimo sullo HTML. Un file HTML è diviso in due grandi blocchi:

<head> … </head>
<body> … </body>

Il primo blocco contiene istruzioni per il browser. Come abbiamo visto, il browser si può permettere addirittura il lusso di ‘ignorarle’ finché non riceve l’ordine preciso di eseguirle. Il secondo blocco (body) invece viene rappresentato subito a schermo.

Facendo un paragone con lo HTML, possiamo azzardare un’affermazione come questa sul C++: possono stare fuori da ogni blocco le istruzioni che non richiedono di essere trasformate in linguaggio macchina, ma istruiscono il compilatore a compiere delle operazioni prima di trasformare il codice in linguaggio macchina.

Non è un’affermazione del tutto precisa perché ci sono istruzioni che non rientrano in questa categoria, ma ora stiamo cercando una regola semplice e generale, anche se passibile di qualche eccezione.

L’istruzione #include <iostream> è infatti un comando al compilatore (copia qui il contenuto del file iostream), non una riga che può essere semplicemente tradotta in linguaggio macchina. Anche using namespace std; è un’istruzione per il compilatore, ma ancora non siamo pronti a esaminarla.

Nel creare due nuove funzioni, vedrete che saremo costretti a scrivere altre due righe fuori da ogni blocco. Anche in quel questo cercheremo di capire se si tratta di istruzioni per il compilatore.


Ordine e pulizia

Il motivo per cui tutto (o quasi!) il codice C++ deve stare all’interno di blocchi è che così è molto, molto più facile riutilizzarlo. Ora impariamo a spezzarlo in blocchi, poi vedremo come questa apparente complicazione ci può in seguito semplificare la vita. Giacché ancora non abbiamo voglia di creare un nuovo progetto, modifichiamo quello su cui stiamo lavorando.

Ancora una cosa: non tutto il codice che scriviamo deve per forza essere trasformato in linguaggio macchina. Possiamo scrivere delle righe che ci servano da promemoria su quello che stiamo facendo e le possiamo scrivere nella nostra lingua, ossia in italiano; il compilatore si limiterà ad ignorarle, giacché lui può capire solo il C++. L’unica avvertenza è iniziare la riga con questo simbolo: ‘//’, che vuol dire: «Ignorami! Non sono C++».

   // Questo è solo un promemoria, una nota, un commento.
   // Il compilatore ignorerà queste righe.

La nostra decisione è di levare le istruzioni che chiedono il nome all’utente e poi lo salutano dalla funzione main e di spostarle in un’altra funzione, che creeremo appositamente. In main, in questa prima fase, non rimarrà quasi niente.

Ossia, main dovrà diventare così:

int main()
{
   *** faccio partire la funzione che chiede il nome all’utente e lo saluta ***
   return 0;
}

Tutto il lavoro lo farà un’altra funzione, di cui dobbiamo decidere il nome. Che ne dite di salutaUtente?

Ecco la nostra funzione:

void salutaUtente()
{
   string utente;

   cout << "Qual è il tuo nome? ";

   cin >> utente;

   cout << "Ciao, " << utente << "!" << endl << endl;
}

La riconoscete? È esattamente ciò che era contenuto nella funzione main: l’ho solo spostato.

Domanda: quale sarà l’istruzione che da main farà partire la funzione salutaUtente? Beh, è assolutamente identica a quella che abbiamo usato nell’elemento <input type="button" dello HTML: il nome della funzione!

Vi ricordate? L’istruzione era onclick="cambioTesto();". Ossia, «quando l’utente fa click su di me, chiama la funzione cambioTesto». Anche nel C++ useremo la stessa sintassi, perciò il rigo mancante in main sarà:

   salutaUtente();

A questo punto ecco il nostro codice completo:


#include <iostream>

void salutaUtente();

using namespace std;

int main()
{
   salutaUtente();
   return 0;
}

void salutaUtente()
{
   string utente;

   cout << "Qual è il tuo nome? ";

   cin >> utente;

   cout << "Ciao, " << utente << "!" << endl << endl;
}

Se non volete fare la fatica di digitare i cambiamenti (però vi farebbe bene fare esercizio!), potete fare il copia incolla, sostituendo questo codice al precedente. Dopodiché salvate, compilate ed eseguite → ossia, premete la freccia verde o CTRL + R, quel che vi piace di più.

Se avete qualche dubbio, ecco come viene la schermata di Qt Creator:

File:Qt_CiaoMondo_4.png

È andato tutto bene? Avete ricevuto qualche messaggio di errore?

Se non avete ricevuto alcun messaggio di errore ci sono 2 possibilità:

  1. siete stati molto attenti e precisi;
  2. avete fatto il copia-incolla :-)

Nel codice è infatti spuntata una riga di cui non vi avevo accennato, la numero 3:

void salutaUtente();

Come vedete, a parte per il punto e virgola finale (TUTTE LE SITRUZIONI C++ FINISCONO CON IL PUNTO E VIRGOLA!!), è del tutto identica all’inizio della funzione che porta lo stesso nome (rigo 13):

void salutaUtente()
{

Che cos’è questo duplicato? E come mai si trova fuori da un blocco?!

Bene, quel duplicato è indispensabile: se non lo mettete, il compilatore si arrabbia e si rifiuta di trasformare il vostro codice in linguaggio macchina. Come mai? Beh, quella riga serve da avvertimento; il suo significato è: «Caro compilatore, ti avverto fin da ora che da qualche parte, nel codice che ho scritto, comparirà la funzione salutaUtente. Quindi fin da ora sei pregato di controllare che non esista un altro blocco di codice che abbia lo stesso nome.»

Vi sembra un’istruzione superflua? Beh, certo: abbiamo scritto un programma di poche righe. Immaginate però di far parte di una squadra e stare scrivendo un programma di migliaia e migliaia di righe, con un sacco di colleghi che tirano fuori nomi di funzioni dal cilindro a ogni piè sospinto. Poniamo il caso che dobbiate scrivere una funzione che cambia l’ordine di due parole in una frase: potrebbe venirvi in mente di chiamarla invertiOrdine. Nello stesso momento però un vostro collega deve scrivere una funzione che chiede al programma di tornare sui suoi passi e di annullare ciò che ha appena fatto; intendendo la parola ‘ordine’ come ‘comando’, chiamerà la sua funzione, guarda un po’, invertiOrdine.

PATATRACK!

Il programma non funzionerà mai.

Stabilendo l’obbligo di elencare all’inizio di ogni file i nomi di funzione contenuti in quel file, il compilatore è invece in grado di accorgersi subito di problemi di questo tipo – e di bloccarsi prima di dare alla luce un programma che farà solo danni.

In realtà l’argomento è molto più complesso, ma per trattarlo dovremmo introdurre il concetto di spazio di visibilità, cosa che faremo tra poco.

I più attenti, osservando il codice, potrebbero chiedersi: «E come mai main non ha una dichiarazione che la precede? Perché non trovo un rigo int main();

Bravi, avete anche messo il punto e virgola alla fine dell’istruzione (io lo dimentico un sacco di volte, con grande irritazione del compilatore). Il motivo è che main è una funzione obbligatoria: è il fischio d’inizio della partita, ricordate? Perciò il compilatore sa già che troverà main e non tollererà che qualcuno scriva un’altra funzione chiamandola main; pertanto, è inutile scrivere un rigo che non aggiunge nulla a ciò che il compilatore sa.

Come vedete anche questa istruzione non serve a essere trasformata in linguaggio macchina, bensì a istruire il compilatore sulle cose che deve fare. Per questo si trova fuori da ogni blocco.


Andiamo avanti con le osservazioni. Paragonate queste due righe, che aprono entrambe una funzione:

rigo 7 → int main()
rigo 13 → void salutaUtente()

Non vi verrebbe da pensare che due righe che aprono entrambe una funzione dovrebbero essere uguali? Perché int main e void salutaUtente? Perché non int salutaUtente?

Continuando a osservare, scopriamo che in main c’è un’istruzione misteriosa che in salutaUtente non c’è:

   return 0;

Riguardando il significato della parola int, ci viene in mente che serve per dichiarare una variabile che può contenere numeri interi, e che per l’appunto il numero 0 è un numero intero… Quindi:

  • int main ↔ return 0;
  • void salutaUtente ↔ nessuna istruzione return.

In inglese void significa ‘privo di’, ‘sprovvisto di’. Ad es., “he was void of any sense of humour”: “era privo di senso dell'umorismo”. Cominciate a sospettare a cosa serve quella parolina prima del nome di funzione? Per capirla meglio, facciamo qualche altro piccolo cambiamento al nostro programma, riportando un po’ di istruzioni dentro main:

#include <iostream>

using namespace std;

string salutaUtente();

int main()
{
   string nome_utente;
   nome_utente = salutaUtente();

   cout << "Ciao, " << nome_utente << "!" << endl << endl;

   return 0;
}

string salutaUtente()
{
   string utente;

   cout << "Qual è il tuo nome? ";

   cin >> utente;

   return utente;
}

Salviamolo e facciamolo partire. Attenzione! È importante invertire le righe string salutaUtente(); e using namespace std; come ho fatto io; questo ci aiuterà a capire il significato di namespace quando ne tratteremo, tra un po’.

Il programma fa sempre la stessa cosa, però, guardate un po’:

  • void salutaUtente() è diventata string salutaUtente()
  • alla fine di salutaUtente c’è un return utente;… e per l’appunto la variabile ‘utente’ è definita di tipo string!

E poi in main è comparsa la misteriosa riga:

nome_utente = salutaUtente();

che riguarda, ancora una volta, una variabile che è stata definita di tipo string nel rigo precedente;

Saranno tutte coincidenze? Beh, no, è chiaro. Rilassatevi, è il momento della spiegazione.

Una funzione è un blocco di codice, ma questo non significa che sia completamente isolata dal codice circostante. A una funzione potete chiedere di modificare il contenuto di variabili che avete creato in un altro blocco di codice (questo lo vederemo più avanti), oppure di rispedirvi indietro il risultato delle sue operazioni.

Facciamo un esempio banale. Mettiamo che dobbiate spegnere un apparecchio che si trova in un’altra stanza. Accanto a voi c’è il pulsante che serve sia per accenderlo che per spegnerlo, però ha un piccolo difetto: una volta premuto, ritorna nella medesima posizione. Cioè, sia che lo premiate per accendere l’apparecchio, sia che lo premiate per spegnerlo, il pulsante rimane sempre uguale.

L’apparecchio si trova in un’altra stanza, non potete né vederlo né udirlo… Come fate a essere sicuri che l’avete spento? E se il pulsante si fosse guastato? Oppure se l’apparecchio fosse già stato spento e voi, premendo il pulsante, l’aveste riacceso? L’unica soluzione sarebbe andare a controllare di persona. Scomodo, vero? E se doveste controllare l’apparecchio più volte in una giornata, tenendolo acceso o spento in momenti diversi?

Insomma, quello che vi farebbe comodo sarebbe un segnale di ritorno, un fischio, una lucina, il fatto che il pulsante si fermi in due posizioni diverse, un indicatore qualsiasi che vi confermi che l’apparecchio è davvero acceso o spento. Ecco, una funzione è in grado di fare proprio questo: può mandarvi un segnale di ritorno, di cui potete fare l’uso che volete. Non solo! La funzione può essere ‘istruita’ a mandare esattamente il segnale di ritorno che scegliete voi.

Questo può essere davvero comodo, e il bello è che ottenere questo risultato è semplicissimo: basta usare la parola chiave return.

Mettiamo di scrivere una funzione che finisca con queste righe:

 return 14;
 }

Bene, il blocco di codice che ha chiamato quella funzione riceverà come segnale di risposta ‘14’. Che significato debba avere questo segnale, è una cosa che deve sapere il programmatore. Nel nostro caso, ad esempio, se volessimo scrivere una funzione che si comporti come quel pulsante, ci farebbe piacere se ci mandasse un segnale di ritorno che comunichi se l’apparecchio, a questo punto, sia acceso o spento. Potrebbe rispondere ‘vero’ (in inglese true) per dire che ora è accesso o ‘falso’ (in inglese false) per confermarci che è spento. La nostra funzione terminerebbe allora con una riga come questa:

 return true;

oppure come questa:

 return false;

Adesso guardiamo passo passo cosa fa il nostro nuovo programma, iniziando direttamente da main.


int main() Entro nella funzione main e inizio con l’eseguire queste istruzioni.


string nome_utente; Creo una variabile. Scelgo come nome ‘nome_utente’ e decido che debba essere idonea a contenere del testo (string).


nome_utente = salutaUtente(); Inserisco un valore nella variabile ‘nome_utente’. Anche se l’istruzione può sembrare strana, è assolutamente identica a scrivere una cosa tipo:

 nome_utente = "Non mi viene in mente nessun nome...";

Alla fine dell’istruzione, dentro la variabile ‘nome_utente’ si troveranno dei dati. La differenza consiste in dove si vanno a prendere i dati da inserire nella variabile ‘nome_utente’. Questa istruzione infatti dice: «Caro computer, i dati che devi inserire nella variabile ‘nome_utente’ non solo altro che il segnale di ritorno che ti invierà la funzione salutaUtente».

A questo punto il nostro povero computer è costretto a saltare dentro l’istruzione salutaUtente, perché lui, di quel segnale di ritorno, ne ha bisogno subito, altrimenti non sa cosa mettere in ‘nome_utente’. Il rigo successivo (cout << "Ciao, "…) non viene quindi eseguito, perché la prossima istruzione che sarà attuata sarà la prima di salutaUtente:


string utente; Creo una variabile. Decido che debba essere idonea a contenere, come tipo di dati, del testo. Decido di chiamarla ‘utente’.


cout << "Qual è il tuo nome? "; Scrivo sullo schermo: Qual è il tuo nome?


cin >> utente; Osservo attentamente la tastiera e, quando l’utente preme il tasto INVIO, copio tutto ciò che ha scritto dentro la variabile ‘utente’ (che è di tipo string).


return utente; Torno indietro al rigo in cui la funzione salutaUtente è stata chiamata (ossia al rigo nome_utente = salutaUtente(); in main), ma mi porto con me, come segnale di ritorno, i dati contenuti nella variabile ‘utente’ (che sono quelli che l’utente ha digitato sulla tastiera). A questo punto ho i dati per completare l’operazione, quindi inserisco nella variabile ‘nome_utente’ di main i dati della del segnale di ritorno (ossia, quelli della variabile ‘utente’ di salutaUtente).


cout << "Ciao, " << nome_utente << "!" << endl << endl; Scrivo a schermo: Ciao + il dati contenuti in ‘nome_utente’ + un punto esclamativo. E poi torno a capo due volte.


return 0; Questo può essere un po’ oscuro: termino il programma inviando il segnale di ritorno di main, ossia quello che comunica al sistema operativo se il programma ha funzionato correttamente o no. Se il sistema operativo si vede recapitare uno 0, lo interpreta come “zero problemi”, ossia “tutto ok”.

A questo punto il significato di quel return dovrebbe essere chiaro, ma come avevo promesso noi creeremo due nuove funzioni, pertanto è giunto il momento di complicarci un altro po’ la vita :-)

Prima di iniziare questa nuova fatica di Sisifo, diamo un attimo un’occhiata a questo banale progettino di Scratch:

File:C++_Qt_01_Scratch_03.png


La parte che ci interessa è quella in basso, in quanto la prima serve solo a risistemare il disegno animato in mezzo alla ‘scena’. Il significato dovrebbe essere chiaro: quando si preme la freccia destra, il personaggio animato si sposta a destra; questo a meno che non sia premuto contemporaneamente anche la freccia in alto, giacché in quel caso il funzionamento della freccia destra si inverte e sposta il disegno verso sinistra.

Quindi il codice dice: SE è vera una determinata condizione, ALLORA fai una certa cosa; ALTRIMENTI fanne un’altra. Domanda retorica: secondo voi questo tipo di costrutto (se… allora) è possibile soltanto in Scratch?

Risposta alla domanda retorica: no, si può fare la stessa cosa in JavaScript e, pensate un po’, pure in C++. Certo, la sintassi è un po’ diversa. Per esempio abbiamo bisogno delle parentesi graffe, perché stiamo dividendo il codice in blocchi. Poi bisogna ricordarsi che:

  • se in inglese si dice if;
  • altrimenti in inglese si dice else.

In C++ scriveremo qualcosa così:

 if (condizione)

 {
    cose da fare se la condizione è vera;
 }

 else

 {
    cose da fare se la condizione è falsa;
 }

Le parentesi graffe dividono il blocco di codice da eseguire quando la condizione è vera da quello da eseguire quando la condizione è falsa. Sono molto importanti perché, quando la condizione è vera, tutto ciò che va da else fino alla fine della parentesi graffa successiva viene saltato a piè pari.

Allo stesso modo, quando la condizione è falsa, tutto il primo blocco di codice, dalla parentesi graffa aperta dopo lo if alla successiva parentesi graffa chiusa, viene scansato e l’esecuzione riprende da else.

Già che ci siamo, tanto vale sapere fin da ora che i programmatori in C++ sono un po’ sadici e amano scrivere il codice tutto appiccicato, al punto che spesso non ci si capisce più niente. Per questo motivo di solito non lasciano righe bianche e portano sul rigo precedente la parentesi graffa aperta. Queste cose non fanno differenza al compilatore, per cui ognuno può scrivere come gli pare, ma tanto vale cominciare a vedere il codice così come lo si trova di solito a giro, ossia più simile a :

 if (condizione) {
    cose da fare se la condizione è vera;
 }
 else {
    cose da fare se la condizione è falsa;
 }

o addirittura a:

 if (condizione) {
    cose da fare se la condizione è vera;
 } else {
    cose da fare se la condizione è falsa;
 }

È il momento di modificare di nuovo il nostro codice, dove abbiamo introdotto un sacco di novità: una nuova funzione, il passaggio di parametri, e dei blocchi ifelse.

Eccolo qua:

#include <iostream>

using namespace std;

int salutaUtente(string nome_utente);
int interrogaUtente();

int main()
{
   int messaggio_per_il_sistema_operativo;
   messaggio_per_il_sistema_operativo = interrogaUtente();

   return messaggio_per_il_sistema_operativo;
}

int interrogaUtente()
{
   string utente;

   cout << "Qual è il tuo nome? ";
   cin >> utente;

   int verifica;
   verifica = salutaUtente(utente);

   if ( verifica == -1 ) {
      cout << "Con te non ci parlo più." << endl << endl;
   }

   return verifica;
}

int salutaUtente(string nome_utente)
{
   int segnale_di_ritorno;

   if ( nome_utente.length() < 3 ) {
      cout << "Hai scritto solo le iniziali!" << endl;
      segnale_di_ritorno = -1;
   }

   else {
      cout << "Ciao, " << nome_utente << "!" << endl << endl;
      segnale_di_ritorno = 0;
   }

   return segnale_di_ritorno;
}

Ormai il codice è così lungo che comincia a non starci più tutto insieme nello schermo, perciò è probabile che questa sia l’ultima immagine in cui si può vedere tutto il codice insieme. Ma ormai siamo bravissimi e non ci serviranno più!


File:Qt_CiaoMondo_5.png


Vediamo un po’ che sorprese ci riserva questo codice.

La prima parte è chiara: facciamo il copia incolla del file iostream, gli diamo un avvertimento su come usarlo (using namespace…), avvertiamo il compilatore che incontrerà ben due funzioni, e in un balletto ci ritroviamo in main.

main ormai non fa quasi niente (vi sorprenderà saperlo, ma è un classico del C++: di solito main contiene pochissime righe di codice). In questo caso, si limita a creare una variabile con un nome lunghissimo e a definirla di tipo intero. Per semplicità d’ora innanzi useremo un’espressione ‘compressa’, ossia diremo: “si limita a creare una variabile intera”, anziché una variabile che è impostata ad accettare dati di tipo intero, un po’ come diremmo ‘un bicchier d’acqua’ invece che un bicchiere di vetro con dell’acqua dentro. I dati da mettere nella variabile devono venire da interrogaUtente, che infatti è impostata per restituire un dato di tipo intero (int interrogaUtente), perciò l’esecuzione ‘salta’ all’interno di questa funzione.

A questo punto:

string utente; → l’abbiamo già vista.

cout << "Qual è il tuo nome? "; → l’abbiamo già vista.

cin >> utente; → l’abbiamo già vista.

int verifica; → dovrebbe ormai essere chiara.

verifica = salutaUtente(utente);

Anche questa istruzione dovrebbe ormai essere chiara. Dice: «Caro computer, i dati (di tipo intero!) che devono essere messi nella variabile ‘verifica’ te li deve dare la funzione salutaUtente

Questo l’abbiamo già visto, ma è la parola utente scritta dopo salutaUtente che rappresenta una novità.

Ripensiamo a quello che abbiamo fatto:

  1. all’inizio abbiamo chiamato delle funzioni che agivano in totale autonomia, come se fossero isolate dal codice circostante. Ad es., la funzione JavaScript cambioTesto andava a cercarsi da sola i dati che le servivano (getElementById…).
  2. Poi abbiamo introdotto delle funzioni che dialogavano con il codice circostante, rimandando indietro un segnale di ritorno (return…).
  3. Adesso dovrebbe essere chiaro qual è il prossimo punto: introdurre delle funzioni che dialogano con il resto del codice dando dei segnali in ingresso alle funzioni che chiamano.

Vi è mai capitato di sentire le persone che si mettono d’accordo così: «Quando arrivi, suona il campanello tre volte, così so che sei tu, non sto nemmeno a risponderti e scendo»?

Faccio un altro esempio: mettiate che di lavoro fate il postino. Il vostro compito è consegnare le lettere nelle cassette della posta. Voi sapete cos’è che dovete fare, ma come fate a sapere in quale cassetta mettere quale lettera? Lo potete scoprire leggendo cosa c’è scritto sulla busta: l’indirizzo del destinatario. In pratica, quando il vostro capo-postino vi chiama: «Ehi, Mario! C’è da recapitare queste lettere!» e vi consegna un sacco pieno di buste; beh, quando fa questo, vi sta dando due informazioni:

  • cos’è che dovete fare (mettere quelle buste nelle rispettive cassette);
  • i dati per farlo (gli indirizzi che sono scritti sulle buste).

Noi ora stiamo facendo la stessa cosa: stiamo creando delle funzioni che, quando ne chiamo altre, dicono loro: «Ehi, sorella funzione, quelle operazioni che devi fare non le devi fare sui dati che ti inventi tu, ma su questi che ti passo io».

Andiamo a vedere com’è che il C++ risolve questo problema. Tanto per essere originale, usa lo stesso metodo che viene usato dal C, e pure i JavaScript lo ha scopiazzato alla stessa maniera, per cui ancora una volta C++ e JavaScript scriverebbero le cose nella stessa maniera.

Il trucco sta nell’informare la funzione di quali dati deve ricevere e di quali deve restituire.

La parolina prima del nome di funzione le dice quali dati deve restituire, e quelle dopo il nome di funzione, dentro la parentesi tonda, le dice quali deve ricevere.

Quindi, una funzione che inizia così:

 int nomeacaso (string nome_di_una_variabile)

accetterà una variabile di tipo string in ingresso e restituirà un segnale di ritorno di tipo int.

Adesso guardiamo come inizia salutaUtente:

int salutaUtente(string nome_utente)

Anche lei accetta una string in ingresso e restituisce un int. Quindi l’istruzione verifica = salutaUtente(utente); significa: «Vai a chiedere alla funzione salutaUtente i dati da mettere nella variabile ‘verifica’. Quando chiami salutaUtente, però, passale i dati contenuti nella variabile ‘utente’, perché lei sa cosa ci deve fare.»

A questo punto siamo entrati nella funzione salutaUtente e le prossime righe che saranno eseguite saranno:

int segnale_di_ritorno; → questa è chiara, ormai, no?

if ( nome_utente.length() < 3 ) {

Questa, lo ammetto è un po’ complicata… Intanto, che cos’è nome_utente? Lo riuscite a capire da soli, leggendo il codice? ‘nome_utente’ è una variabile di tipo string che è creata all’inizio della funzione salutaUtente, ossia dove è scritto:

 int salutaUtente(string nome_utente)

Vedete tra parentesi la scritta string nome_utente? È lì che ‘nome_utente’ utente viene creata, e definita di tipo string. Se l’inizio di salutaUtente fosse stato:

 int salutaUtente()
 {
 string nome_utente;

avremmo ottenuto esattamente la stessa variabile.

Non c’è alcuna differenza, allora? No, c’è una differenza: essendo la variabile che si trova subito dopo il nome della funzione, è lei che riceve i dati in ingresso! In altre parole, il valore della variabile ‘utente’ di interrogaUtente viene copiato nella variabile ‘nome_utente’ di salutaUtente appena creata.

Ossia, già prima di entrare dentro la funzione salutaUtente, si è verificato questo fatto:

‘nome_utente’ di salutaUtente = ‘utente’ di interrogaUtente.

Adesso possiamo usare ‘nome_utente’ sapendo che contiene gli stessi dati di ‘utente’ di interrogaUtente, e tutto ciò senza influenzare ‘utente’. Infatti i dati vengono copiati e questo vuol dire che non rimane alcun collegamento fra ‘nome_utente’ e ‘utente’: ciò che faremo a ‘nome_utente’ non avrà alcun riflesso su ‘utente’.

Quindi noi stiamo usando ‘nome_utente’ che contiene una COPIA di ciò che l’utente ha digitato sulla tastiera.

Ciò che noi vogliamo fare è:

  1. controlliamo quanti caratteri ci sono nella variabile ‘nome_utente’;
  2. se sono meno di 3, allora vuol dire che l’utente non ha scritto il suo vero nome, ma magari solo le iniziali, e questo a noi non piace :-) Quindi, mandiamo un messaggio di protesta.
  3. Se invece i caratteri sono almeno 3, che potrebbe essere vero per “Ugo”, allora salutiamo l’utente come abbiamo fatto fin’ora.

Vediamo di capire come funziona quanto sopra in C++.

lenght è un’altra parolina magica il cui relativo codice è contenuto in iostream. Se appiccichiamo questa parolina a una variabile string tramite un punto, lei ci restituisce la lunghezza della stringa di testo che è contenuta in quella variabile.

Avete notato che lenght è seguita da parentesi tonde? Ossia che è scritta così: lenght()? Vi fa venire in mente niente, questo? Quand’è che una parolina è seguita da parentesi tonde? Esatto: quando è un nome di funzione. Perciò abbiamo scoperto che lenght() è una funzione. In particolare, è una funzione che restituisce il numero di caratteri di una variabile di tipo string. In realtà è una funzione di un tipo particolare, di quei tipi che devono essere attaccati ad un’altra parolina per funzionare. Questo tipo di funzioni si chiamano metodi e per ora li dobbiamo usare senza chiederci perché devono stare attaccati a un’altra parola.

In conclusione: il significato di questa riga è: «Se la lunghezza di ‘nome_utente’ è inferiore a 3 (caratteri), allora…»

cout << "Hai scritto solo le iniziali!" << endl; → questo dovrebbe essere chiaro.

segnale_di_ritorno = -1;

Il contenuto delle variabile ‘segnale_di_ritorno’, di tipo int, deve diventare -1. Ricordo che anche i numeri negativi sono interi: basta che non abbiano decimali.

else { → altrimenti…

cout << "Ciao, " << nome_utente << "!" << endl << endl; → già visto.

segnale_di_ritorno = 0; → il contenuto di ‘segnale_di_ritorno’ deve essere 0.

return segnale_di_ritorno;

Se ‘nome_utente’ aveva meno di 3 caratteri, e quindi è stata eseguita la prima parte del blocco if…else, salutaUtente restituirà -1. Se ‘nome_utente’ aveva 3 caratteri o più, è stato eseguito solo il blocco dopo else e quindi salutaUtente restituirà 0. Ricordo che, al contrario di quello che si può pensare, è consuetudine interpretare 0 come il segnale di “tutto a posto”, come a dire: “zero errori!”.

A questo punto il computer ritorna in interrogaUtente ed esegue:

if ( verifica == -1 ) { «Se salutaUtente ha restituito -1, allora…»

cout << "Con te non ci parlo più." << endl << endl; → penso sia chiaro.

return verifica;

Per motivi puramente didattici, ossia per abituarsi a veder succedere queste cose, rimando al chiamante di interrogaUtente lo stesso valore che interrogaUtente ha avuto da salutaUtente.

Siamo ormai tornati in main e la prossima riga ad essere eseguita sarà:

return messaggio_per_il_sistema_operativo; Ho scelto un nome lunghissimo (e scomodissimo! È una cosa da non fare mai) per la variabile in modo che fosse chiaro a chi finisce quello 0 o -1 che è partito due funzioni più giù. Il significato complessivo però, ormai dovrebbe essere chiaro.

Non se se davvero può essere d’aiuto, comunque ho preparato un’immagine che dovrebbe aiutare a visualizzare meglio ciò che abbiamo detto fin’ora. Eccola:

File:Qt_CiaoMondo_5_freccette.png


Come farsi odiare

Bene, non credo che questo programmino possa darci molto di più.

L’unica cosa che vorrei sottolineare, ma non è poi così importante, è che le funzioni restituiscono comunque il valore che devono restituire, anche se noi non lo mettiamo in una variabile. In realtà anche nome_utente.length() ha restituito un valore int, ma noi abbiamo usato quel valore di ritorno per fare un paragone con il numero 3 senza preoccuparci di salvarlo in una variabile.

Avremmo anche potuto scrivere:

int salutaUtente(string nome_utente)
{
   int segnale_di_ritorno;

   int lunghezza = nome_utente.length(); // Questa riga non c'era

   if ( lunghezza < 3 ) { // Questa riga è un po' diversa
      cout << "Hai scritto solo le iniziali!" << endl;
      segnale_di_ritorno = -1;
   }

   else {
      cout << "Ciao, " << nome_utente << "!" << endl << endl;
      segnale_di_ritorno = 0;
   }

   return segnale_di_ritorno;
}

Il codice soprastante funziona senza problemi, ma i programmatori in C++ odiano queste cose. L’avete capito, no? Tutto deve essere strizzato, senza spazi inutili; se una variabile non è indispensabile, allora va eliminata senza pietà!

Perciò, sempre a scopo puramente didattico, ossia per farvi vedere che i valori di ritorno si possono usare anche senza salvarli in delle variabili, vi propongo lo stesso codice, sempre perfettamente funzionante, però con un numero ridotto di righe di codice nonché di variabili.

Vi avverto che, pur sapendo perfettamente cosa fa, leggerlo può risultare un po’ complicato!

#include <iostream>

using namespace std;

int salutaUtente(string nome_utente);
int interrogaUtente();

int main()
{
   return interrogaUtente();
}

int interrogaUtente()
{
   string utente;
   cout << "Qual è il tuo nome? ";
   cin >> utente;

   int verifica = salutaUtente(utente);
   if ( verifica == -1 ) {
      cout << "Con te non ci parlo più." << endl << endl;
   }

   return verifica;
}

int salutaUtente(string nome_utente)
{
   int segnale_di_ritorno = 0;

   if ( nome_utente.length() < 3 ) {
      cout << "Hai scritto solo le iniziali!" << endl;
      segnale_di_ritorno = -1;
   }
   else {
      cout << "Ciao, " << nome_utente << "!" << endl << endl;
   }

   return segnale_di_ritorno;
}