https://kata.coderdojo.it/wiki/index.php?title=Speciale:PaginePi%C3%B9Recenti&feed=atom&hideredirs=1&limit=50&offset=&namespace=0&username=&tagfilter=
WIKI CoderDojo Firenze - Pagine più recenti [it]
2024-03-29T08:16:17Z
Da WIKI CoderDojo Firenze.
MediaWiki 1.23.2
https://kata.coderdojo.it/wiki/index.php?title=Python%2BMinecraft:_primi_esercizi
Python+Minecraft: primi esercizi
2016-05-24T22:15:38Z
<p>Fpiantini: /* Esercizio 2: Seminare funghi... */</p>
<hr />
<div>Gli esercizi descitti in questa pagina sono stati adattati a partire da quelli messi a disposizione dal repository [https://github.com/teachthenet/TeachCraft-Challenges TeachCraft-Challenges]. Si ringrazia [https://github.com/teachthenet TeachTheNet] per l'interessante materiale messo a disposizione.<br />
<br />
== Prerequisiti ==<br />
<br />
Deve essere stato installato l'interprete Python e il launcher Minecraft come descritto in [http://kata.coderdojo.it/wiki/index.php?title=Python_-_Minecraft:_Setup_PC_dei_Partecipanti un'altra pagina di questo sito]. Deve essere disponibile un server Minecraft che disponga di un'interfaccia API in Python a cui collegarsi in modalità multiplayer.<br />
<br />
Nel caso non lo avessete a disposizione in questo sito è disponibile [http://kata.coderdojo.it/wiki/index.php?title=Python_-_Minecraft:_setup_di_un_server_Minecraft una pagina] che descrive come installarlo e avviarlo.<br />
<br />
Nel seguito supponiamo che il server sia disponibile all'indirizzo IP '''192.168.12.10'''.<br />
<br />
== Avviare il Launcher Minecraft ==<br />
<br />
Per avviare il launcher Minecraft fare doppio click sull'icona '''Minecraft_Launcher.jar''' presente nella directory '''TeachCraft-Challenges''' preparare al punto precedente. In alternaltiva lanciare da terminale con il comando:<br />
<pre>$ java -jar Minecraft_Launcher.jar<br />
</pre><br />
Una volta che il caricamento del launcher è terminato apparirà la seguente finestra:<br />
<br />
[[File:TLauncher 1.964 217.png|600px|File:TLauncher_1.964_217.png]]<br />
<br />
=== Configurazione ===<br />
<br />
Per evitare che tutte le volte che ci allontaniamo dalla finestra di Minecraft questa si disattivi, occorre modificare la configurazione di Minecraft.<br />
In particolare occorre aprire il file di configurazione e modificare il parametro '''pauseOnLostFocus''' impostandolo al valore '''false''':<br />
<br />
<pre><br />
pauseOnLostFocus:false<br />
</pre><br />
<br />
Per accedere al file di configurazione cliccare sul pulsante "Game Folder" in basso a destra della finestra del Launcher. All'interno della finestra che si aprirà cercare il file '''options.txt'''; aprirlo con un editor e modificare il parametro come indicato sopra.<br />
<br />
=== Collegamento al server ===<br />
<br />
Cliccare su '''Enter the Game''' in basso a destra. Attendere il caricamento di Minecraft. Apparirà la seguente finestra:<br />
<br />
[[File:Minecraft 1.8.8 218.png|600px|File:Minecraft_1.8.8_218.png]]<br />
<br />
A questo punto cliccare sul pulsante '''Multiplayer'''. Apparirà una nuova finestra con una serie di pulsanti, scegliere '''Direct connect'''. Appare un'ulteriore finestra dove inserire l'indirizzo IP del server (nel nostro caso, come esempio, 192.168.12.10):<br />
<br />
[[File:Minecraft 1.8.8 219.png|600px|File:Minecraft_1.8.8_219.png]]<br />
<br />
Cliccare su '''Join Server'''. Se tutto andrà a buon fine ci si troverà all'interno di un paesaggio Minecraft. Possiamo finalmente iniziare gli esperimenti con Python.<br />
<br />
== Scrivere il primo programma Python ==<br />
<br />
Questo esercizio insegna come aprire una connessione con il server Minecraft per realizzare una semplice operazione di scrittura sulla chat del gioco.<br />
<br />
Aprire l'editor che si è scelto per scrivere il programma Python e inserire le seguenti righe:<br />
<br />
<syntaxhighlight lang="python" line ><br />
import mcpi.minecraft as minecraft<br />
mc = minecraft.Minecraft.create(address="192.168.12.10", name="rodmcban")<br />
mc.postToChat("Ciao Minecraft!")<br />
</syntaxhighlight><br />
<br />
Al posto dell'indirizzo assegnato alla variabile '''address''' inserire l'indirizzo del server a cui si è collegati (quello inserito nella finestra precedente nel campo server address) e come '''"name"''' utilizzare quello del proprio personaggio (inserito all'inizio nella prima schermata del launcher).<br />
<br />
Salvare il file così scritto all'interno della directory '''TeachCraft-Challenges'''.<br />
<br />
Eseguire il programma Python con l'interprete che si ha a disposizione. Sulla finestra di Minecraft apparirà una riga di chat con scritto '''"Ciao Minecraft!"'''<br />
<br />
[[File:Minecraft 1.8.8 221.png|600px|File:Minecraft_1.8.8_221.png]]<br />
<br />
Vediamo nel dettaglio cosa significano le tre righe che abbiamo scritto.<br />
<br />
<syntaxhighlight lang="python" line ><br />
import mcpi.minecraft as minecraft<br />
</syntaxhighlight><br />
<br />
Questa prima riga serve per spiegare a Python che abbiamo intenzione di utilizzare la libreria '''mcpi''' che è quella che fornisce le funzionalità per comunicare con il server Minecraft. Non realizza nessuna operazione visibile, ma dice a Python che vogliamo inviare dei comandi a Minecraft.<br />
<br />
<syntaxhighlight lang="python" line start="2" ><br />
mc = minecraft.Minecraft.create(address="192.168.12.10", name="rodmcban")<br />
</syntaxhighlight><br />
<br />
Questa seconda riga dice a Python di collegarsi al server Minecraft che si trova all'indirizzo '''192.168.12.10''' e, su questo server, agganciarsi al personaggio di nome '''rodmcban'''.<br />
<br />
Queste due righe, che ancora non fanno nulla di visibile, sono obbligatorie per tutti i programmi che scriveremo: senza di queste infatti Python non è in grado di sapere come interpretare i comandi che seguono.<br />
<br />
Notare la variabile '''mc''': in questo "contenitore" viene salvata la connessione con il personaggio che abbiamo scelto. D'ora in avanti, quando useremo questa variabile, Python capirà che vogliamo fare un'operazione con quello specifico personaggio.<br />
<br />
Con queste prime due righe abbiamo stabilito la comunicazione con Minecraft, ma, se ci fermassimo qui, non succederebbe niente. Diciamo che avremmo scritto un programma inutile: apriamo una connessione ma poi non ci facciamo niente. Il succo di questo semplicissimo programma è nella terza istruzione:<br />
<br />
<syntaxhighlight lang="python" line start="3" ><br />
mc.postToChat("Ciao Minecraft!")<br />
</syntaxhighlight><br />
<br />
Con questa istruzione diciamo a Python di eseguire un'operazione con la variabile '''mc''' (e quindi verso il personaggio che abbiamo scelto). In particolare l'operazione che chiediamo di eseguire è '''postToChat''' che mostra un messaggio sulla chat del personaggio.<br />
<br />
== Esercizio 1: Teletrasportare il personaggio ==<br />
<br />
Con questo secondo programma vediamo come inviare un comando che cambia la posizione del personaggio a cui siamo agganciati. L'esempio è tratto dalla [https://github.com/teachthenet/TeachCraft-Challenges/blob/master/lesson_1.md prima lezione] del sito TeachCraft-Challenges.<br />
<br />
Il codice da scrivere stavolta è leggermente di più:<br />
<br />
<syntaxhighlight lang="python" line ><br />
# coding=utf-8<br />
import mcpi.minecraft as minecraft<br />
<br />
# NOTA - sostituire l'indirizzo IP 192.168.12.10 con quello del server a cui<br />
# si è collegati e "rodmcban" con il nome del proprio personaggio<br />
mc = minecraft.Minecraft.create(address="192.168.12.10", name="rodmcban")<br />
<br />
mc.player.setPos(-33, 20, 34)<br />
</syntaxhighlight><br />
<br />
Qui introduciamo i '''commenti''' che sono le righe che iniziano con il carattere '''#'''.<br />
Queste righe servono a noi per ricordarci qualcosa sul codice che stiamo scrivendo ma sono completamente ignorate dall'interprete Python. Di fatto non servono all'esecuzione del programma<br />
<br />
A parte i commenti riconosciamo le prime due righe di codice, che altro non sono che quelle che già conosciamo e che servono a stabilire una connessione con un personaggio sul server.<br />
<br />
La terza riga che è quella che effettua veramente un'operazione questa volta utilizza il metodo '''setPos''' per impostare la posizione del personaggio a dove vogliamo noi.<br />
<br />
Provate a spostarvi per il mondo Minecraft dove volete e poi provate ad eseguire questo nuovo programma: tornerete tutte le volte a una posizione predefinita.<br />
<br />
=== Concetto di programmazione: le VARIABILI ===<br />
<br />
Usciamo adesso un attimo dal mondo Minecraft e parliamo di un concetto molto importante della programmazione: le '''variabili'''. <br />
<br />
Immaginate una variabile come un contenitore che contiene un valore. Per esempio L'istruzione:<br />
<br />
<syntaxhighlight lang="python" line ><br />
v = 1000<br />
</syntaxhighlight><br />
<br />
assegna alla variabile '''v''' il valore '''1000'''. Quando nel seguito faremo riferimento alla variabile '''v''' semplicemente otterremo il valore '''1000'''. Per esempio proviamo a scrivere ed eseguire il seguente programma:<br />
<br />
<syntaxhighlight lang="python" line ><br />
v = 1000<br />
print "la variabile di nome v vale: ", v<br />
</syntaxhighlight><br />
<br />
Il programma salva dentro la variabile '''v''' il valore '''1000''' e successivamente stampa sulla console un messaggio e il valore della variabile v. (Incidentalmente abbiamo scoperto la funzione '''print''', una funzione molto comoda che stampa messaggi sulla finestra dove eseguiamo il programma (la ''console'')).<br />
<br />
Scriviamo adesso una versione leggermente più complicata del programma di teletrasporto utilizzando delle '''variabili''' per indicare le tre componenti della posizione '''x''', '''y''' e '''z''':<br />
<br />
<syntaxhighlight lang="python" line ><br />
# coding=utf-8<br />
import mcpi.minecraft as minecraft<br />
<br />
# NOTA - sostituire l'indirizzo IP 192.168.12.10 con quello del server a cui<br />
# si è collegati e "rodmcban" con il nome del proprio personaggio<br />
mc = minecraft.Minecraft.create(address="192.168.12.10", name="rodmcban")<br />
<br />
x = -33<br />
y = 20<br />
z = 34<br />
<br />
mc.player.setPos(x, y, z)<br />
</syntaxhighlight><br />
<br />
<br />
=== Esercizi ===<br />
<br />
* Provare a modificare i valori dei tre argomenti della funzione '''setPos'''. Cosa succede?<br />
* Quale tra '''x''', '''y''' e '''z''' è quello che cambia la posizione verticale del personaggio?<br />
* Scrivere un programma python che calcola il risultato dell'operazione '''2 + 3''', lo memorizza in una variabile e lo stampa nella console<br />
<br />
== Esercizio 2: Seminare funghi... ==<br />
<br />
I programmi visti finora facevano una singola cosa e poi terminavano.<br />
Con il nuovo programma che stiamo per scrivere sperimenteremo una istruzione che ci permetterà di ripetere un ciclo di istruzioni più volte.<br />
<br />
L'istruzione si chiama '''while''' e significa '''ripeti fino a quando'''. In pratica questa istruzione ripete una o più operazioni finché una condizione rimane vera. Siccome noi in questo primo programma vogliamo ripetere un gruppo di istruzioni '''per sempre''' utilizzeremo un caso particolare del ciclo while che è il '''while True''' dove '''True''' e una variabile logica che significa '''Vero'''. Per questo '''while True''' significa in soldoni '''ripeti per sempre'''.<br />
<br />
Adesso dobbiamo capire un'altra cosa: con l'istruzione '''while''' noi non vogliamo ripetere per sempre non una singola cosa, ma un blocco di istruzioni. Come facciamo a riconoscere quali sono le istruzioni che devono essere ripetute? O in parole più tecniche il '''blocco''' di istruzioni da ripetere?<br />
<br />
Per questo in Python utilizziamo '''l'indentazione''' e cioè mettiamo all'inizio della riga un carattere '''TAB''' (quello che abbiamo sulla nostra tastiera a sinistra sopra il tasto che ci permettere di stampare i caratteri maiuscoli).<br />
<br />
Ecco alla fine come apparirà il nostro programma, con un po' di commenti che ci spiegano cosa sta succedendo:<br />
<br />
<syntaxhighlight lang="python" line ><br />
# coding=utf-8<br />
import time<br />
<br />
import mcpi.minecraft as minecraft<br />
mc = minecraft.Minecraft.create(address="192.168.12.10", name="rodmcban")<br />
<br />
# I blocchi utilizzati in Minecraft hanno un codice numerico.<br />
# L'elenco dei codici è reperibile al seguente indirizzo:<br />
# http://minecraft-ids.grahamedgecombe.com/<br />
#<br />
# Utilizziamo il blocco 40, che rappresenta dei funghi:<br />
block = 40<br />
<br />
print "Prima del ciclo."<br />
<br />
while True:<br />
# Recupera la posizione corrente del giocatore (coordinate X, Y e Z)<br />
# e le salva nella variabile pos:<br />
pos = mc.player.getPos()<br />
<br />
# Estrae dalla variabile pos il valore delle coordinate<br />
# e le salva nelle variabili x, y, z<br />
x = pos.x<br />
y = pos.y<br />
z = pos.z<br />
<br />
# <br />
# Cambia il blocco che si trova immediatamente dietro<br />
# il personaggio al tipo di blocco che abbiamo scelto<br />
# in precedenza<br />
mc.setBlock(x-1, y, z, block)<br />
<br />
# Usa la funzione print per stampare la posizione del giocatore <br />
# e quindi torna all'inizio del ciclo<br />
print "Posizione = ", int(x), ", ", int(y), ", ", int(z), " --- Aspettiamo 0.2 secondi e ripetiamo il ciclo"<br />
time.sleep (0.2)<br />
<br />
print "fuori dal ciclo"<br />
<br />
</syntaxhighlight><br />
<br />
Provate a muovervi per lo schermo e osservare cosa succede.<br />
<br />
=== Esercizi ===<br />
* Provare a cambiare il tipo di blocco che viene generato dietro il personaggio<br />
* Invece di mettere il blocco dietro il personaggio provare a metterlo sotto oppure a destra e a sinistra<br />
<br />
Alcuni tipi di blocchi interessanti:<br />
<br />
<pre><br />
1 Stone (minecraft:stone)<br />
9 Still Water (minecraft:water)<br />
11 Still Lava (minecraft:lava)<br />
17 Oak Wood (minecraft:log)<br />
20 Glass (minecraft:glass)<br />
22 Lapis Lazuli Block (minecraft:lapis_block)<br />
37 Dandelion (minecraft:yellow_flower)<br />
41 Gold Block (minecraft:gold_block)<br />
42 Iron Block (minecraft:iron_block)<br />
</pre><br />
<br />
== TO BE CONTINUED ==<br />
<br />
[[Category:Python|P]]<br/>[[Category:Minecraft|M]]</div>
Fpiantini
https://kata.coderdojo.it/wiki/index.php?title=Python_-_Minecraft:_setup_di_un_server_Minecraft
Python - Minecraft: setup di un server Minecraft
2016-05-24T22:06:28Z
<p>Fpiantini: </p>
<hr />
<div>= Setup Server Minecraft per programmazione con Python =<br />
<br />
In questa pagina è descritta una possibile procedura per mettere in piedi un server Minecraft da utilizzare per gli esercizi di programmazione in Python contenuti in questo sito (per esempio quelli contenuti nella pagina&nbsp;[[Python+Minecraft: primi esercizi|primi esercizi]]<br />
<br />
=== Scaricamento Server ===<br />
<br />
Il server scelto è CanaryMod. Si è scelto di utilizzare la versione [https://github.com/teachthenet/TeachCraft-Server TeachCraft reperibile su GitHub].<br />
<br />
Per scaricare il server su un PC con il comando GIT disponibile si può dare il seguente comando:<br />
<pre>$ git clone https://github.com/teachthenet/TeachCraft-Server.git<br />
</pre><br />
Oppure si può scaricare direttamente l'archivio dalla [https://github.com/teachthenet/TeachCraft-Server/archive/master.zip stessa pagina su GitHub] oppure dall'[http://kata.coderdojo.it/archivio/20_python_minecraft/TeachCraft-Challenges/TeachCraft-Server.tar.gz archivio del Coderdojo di Firenze].<br />
<br />
Espandere l'archivio utilizzando il comando tar o unzip da terminale Linux, o aprendolo con un programma in grado di leggere tar compressi o zip (su Windows per esempio si consiglia [http://www.7-zip.org/ 7zip]).<br />
<br />
=== Installazione Java ===<br />
<br />
Per eseguire il server è necessario avere a disposizione il runtime environment (JRE) o la JDK Java. Per installarla utilizzare le indicazioni contenute nella [http://kata.coderdojo.it/wiki/index.php?title=Python_-_Minecraft:_Setup_PC_dei_Partecipanti#Installazione_Java sezione all'interno della pagina] che descrive come installare il launcher nei PC dei partecipanti<br />
<br />
=== Lancio Server ===<br />
<br />
Aprire un terminale e andare nella directory dove si è decompresso il file al passo precedente. Dare il comando:<br />
<pre>$ java -Xms3036M -Xmx3036M -jar CanaryMod-1.2.0.jar<br />
</pre><br />
La quantità di memoria da assegnare al processo (specificata con i parametri -Xms e Xmx) deve essere adattata in base alle caratteristiche della macchina server che si sta utilizzando. Per esempio se si sta utilizzando un Raspberry PI 2 utilizzare 512 Mbytes:<br />
<pre>$ java -Xms512M -Xmx512M -jar CanaryMod-1.2.0.jar<br />
</pre><br />
Attendere che il server termini la procedura di caricamento. Può metterci da pochi secondi a diverse decine a seconda della potenza della scheda o del PC dove si sta eseguendo lo stesso.<br />
<br />
<br />
<br />
<br/><br/><br/>TO BE COMPLETED<br />
[[Category:Python|P]]<br/>[[Category:Minecraft|M]]</div>
Fpiantini
https://kata.coderdojo.it/wiki/index.php?title=Cells
Cells
2016-05-22T12:50:43Z
<p>Mbert: </p>
<hr />
<div>= <font face="Trebuchet MS, sans-serif">Cells</font> =<br />
<br />
<font face="Trebuchet MS, sans-serif">Il file 'cells.html' (trovate tutto in [[Media:Cells.zip|Cells.zip]]) realizza un gioco ispirato a ciò che è stato detto all'ultima riunione su agar.io. Il concetto è cellula grande mangia cellula piccola. Il giocatore controlla il movimento della cellula blu, il computer (ovvero il caso) controlla le altre cellule, rosse o cambiando il commento di colore casuale.</font><br />
<br />
<font face="Trebuchet MS, sans-serif">La parte html ha un titolo, una riga per punteggio e record e l'elemento canvas che consente di disegnare il campo da gioco e le cellule in movimento.</font><br />
<br />
<font face="Trebuchet MS, sans-serif">Il codice inizia con la definizione delle variabili, una serie di funzioni, la gestione dei tasti freccia e la chiamata alla funzione 'init' che crea la cellula del giocatore, le altre cellule ed il loop del gioco.</font><br />
<br />
<font face="Trebuchet MS, sans-serif">La funzione 'scena' controlla lo svolgimento del gioco, muove la cellula del giocatore in base ai tasti premuti e le altre cellule casualmente. Controlla se qualche cellula mangia altre cellule o esce dallo schermo. Quando una cellula mangia cresce, quando viene mangiata o esce dallo schermo esce dal gioco. Il giocatore vince quando rimane l'unica cellula o cresce troppo. Perde quando viene mangiato o esce dallo schermo. Ad ogni ciclo del gioco e ogni volta che una cellula viene mangiata, può nascere una nuova cellula.</font><br />
[[Category:Javascript|C]]</div>
Mbert
https://kata.coderdojo.it/wiki/index.php?title=Python_-_Minecraft:_Setup_PC_dei_Partecipanti
Python - Minecraft: Setup PC dei Partecipanti
2016-05-20T22:18:32Z
<p>Fpiantini: /* Interprete Python 2.7 */</p>
<hr />
<div>= Setup PC partecipanti a eventi Python / Minecraft =<br />
<br />
In questa pagina viene indicato come preparare i PC per partecipare agli eventi Python+Minecraft organizzati dal Coderdojo di Firenze.<br />
<br />
== Installazione Software di base ==<br />
<br />
Sul PC deve essere presente un buon editor di codice (per intendersi Notepad non va bene...).<br />
<br />
Se ne avete uno preferito potete utilizzarlo, altrimenti, se non avete idee, potete seguire i nostri consigli utilizzando i seguenti:<br />
<br />
*MS Windows: [https://notepad-plus-plus.org/download Notepad++]<br />
<br />
*OSX: [http://www.barebones.com/products/textwrangler/download.html TextWrangler]<br />
<br />
*Linux: le installazioni standard prevedono la presenza di editor di buona qualità come Gedit o Kate, per cui non è necessario installare niente di addizionale<br />
<br />
E' poi possibile anche utilizzare degli ambienti più "sofisticati". Una buona IDE per Python è ad esempio [https://www.jetbrains.com/pycharm/download/ PyCharm versione Community].<br />
<br />
== Interprete Python 2.7 ==<br />
<br />
*Windows / OSX: scaricare e installare la versione appropriata dell'interprete dalla [http://www.python.it/download/ pagina del progetto Python]<br />
<br />
*Linux: a seconda della distribuzione utilizzare l'appropriato comando. Per esempio per Ubuntu e derivati utilizzare il comando da terminale:<br />
<pre>sudo apt-get install python</pre><br />
<br />
'''N.B.: E' IMPORTANTE INSTALLARE LA VERSIONE 2.7. LA VERSIONE 3.5 NON E' COMPATIBILE CON LA LIBRERIA UTILIZZATA PER PARLARE CON MINECRAFT.'''<br />
<br />
== Installazione Java ==<br />
<br />
Normalmente i PC con sistema operativo Windows o Mac OSX hanno già il software Java installato. L'unica cosa importante è che la versione Java installata sia la 8 (detta anche 1.8). Nel caso sia necessario installarla andare sul [http://www.java.com/en/download/ sito ufficiale di Java] e scaricare la JDK appropriata per la macchina in preparazione<br />
<br />
Per i sistemi operativi Linux occorre essere sicuri che la versione di Java installata sia quella ufficiale della Oracle e non una versione diversa (per esempio la OpenJDK). Per installare La Oracle Java seguire ad esempio [http://askubuntu.com/questions/56104/how-can-i-install-sun-oracles-proprietary-java-jdk-6-7-8-or-jre questa guida su AskUbuntu]. Per scaricare java andare nella [http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html pagina relativa] sul sito Oracle. Scaricare la versione appropriata al PC che si sta utilizzando (in base al sistema operativo e al tipo di architettura, 32 o 64 bits). Per verificare la versione di Java aprire un terminale e dare il comando:<br />
<pre>java -version</pre><br />
Devono essere stampate stringhe nella forma:<br />
<pre>$ java -version<br />
<br />
java version "1.8.0_91"<br />
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)<br />
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)<br />
<br />
$ _<br />
</pre><br />
== Installazione Launcher Minecraft ==<br />
<br />
Se il programma Minecraft è già installato sul PC non è necessario fare niente (passare al capitolo "Collegamento al server").<br />
<br />
Per installare invece il launcher, scaricarlo da [http://kata.coderdojo.it/archivio/20_python_minecraft/TeachCraft-Challenges/TeachCraft-Challenges-master.zip questo link] dall'archivio del coderdojo di Firenze. Altrimenti è possibile scaricarlo direttamente dalla [https://github.com/teachthenet/TeachCraft-Challenges pagina GitHub del progetto TeachCraft-Challenges].<br />
<br />
Una volta copiato il pacchetto sul PC, effettuare l'unzip del file in una directory a piacere. Cliccare sull'icona "Minecraft_Launcher.jar" per effettuare l'installazione del pacchetto Minecraft. La prima volta che il programma viene lanciato potrebbe apparire una finestra che indicare che è stata trovata una versione aggiornata del launcher. Cliccare su "Yes" per effettuare l'aggiornamento. A questo punto appare una finestra "TLauncher". Effettuare i seguenti passi:<br />
<br />
*In basso a sinistra inserire uno user name a piacere<br />
*Sempre in basso a sinistra selezionare la release del server, selezionare il valore "Release 1.8.8"<br />
*Cliccare sul pulsante "Install" in basso al centro<br />
<br />
Lasciare terminare l'aggiornamento e l'installazione. Alla fine della procedura, oppure lanciando nuovamente il "Minecraft_Launcher.jar" apparirà la seguente finestra (o qualcosa di simile):<br />
<br />
[[File:TLauncher 1.964 217.png|File:TLauncher_1.964_217.png]]<br />
<br />
Adesso è possibile provare a collegarsi al server e scrivere i primi programmi Python. Cominciare per esempio dall'esercizio descritto nella pagina [[Python+Minecraft: primi esercizi|Python+Minecraft: primi esercizi]]<br />
[[Category:Python|P]]<br />
[[Category:Minecraft|M]]</div>
Fpiantini
https://kata.coderdojo.it/wiki/index.php?title=App_Inventor:_Installazione
App Inventor: Installazione
2016-05-03T22:02:43Z
<p>Leoncino: </p>
<hr />
<div>== Installazione App Inventor su server locale ==<br />
<br />
Scopo di questa pagina è descrivere come installare ed utilizzare il server di App Inventor 2 su un server locale Linux da utilizzare poi per sessioni di Coderdojo.<br />
<br />
Il progetto App Inventor è Open Source ed è liberamente scaricabile da GitHub nella [https://github.com/mit-cml/appinventor-sources pagina appositamente predisposta].<br />
<br />
Su internet è anche reperibile [https://docs.google.com/document/pub?id=1Xc9yt02x3BRoq5m1PJHBr81OOv69rEBy8LVG_84j9jc un documento] molto dettagliato con informazioni su come preparare il server su vari sistemi (Linux, MacOS, Windows). Si rimanda a questo documento per informazioni dettagliate, qui ci si limita a riportare i passi principali.<br />
<br />
Risultano poi presenti altre risorse tra cui un [https://groups.google.com/forum/#!forum/app-inventor-open-source-dev Forum].<br />
<br />
Interessante anche il documento [https://docs.google.com/document/d/1hIvAtbNx-eiIJcTA2LLPQOawctiGIpnnt0AvfgnKBok/pub App Inventor Deveper Overview].<br />
<br />
Nella pagina del progetto su GitHub sono contenute altre informazioni interessanti.<br />
<br />
<br />
<br />
=== Prerequisiti ===<br />
<br />
Il primo prerequisito importante è che sia installata la SDK completa di Java nella versione Oracle 1.7 (a.k.a. 7). Attenzione sui sistemi Ubuntu che di default installano OpenJdk. Da notare che di default oggi viene installata la 1.8 e che nella documentazione di App Inventor insistono molto nell'usare la versione 1.7.<br />
<br />
Altri programmi necessari:<br />
<br />
*git<br />
*ant<br />
<br />
<br />
<br />
=== Installazione Google App Engine ===<br />
<br />
Occorre avere a disposizione un'installazione di [https://cloud.google.com/appengine/downloads Google App Engine] per Java. Scaricarla da sito e installarla seguendo le indicazioni riportate sullo stesso (sostanzialmente unzip del file). Da notare che nella documentazione App Inventor si insiste molto nell'usare la versione di App Engine non superiore alla 1.9.27.<br />
<br />
Dopo l'unzip inserire il percorso &lt;directory_app_engine&gt;/bin nel PATH<br />
<br />
=== Compilazione App Inventor ===<br />
<br />
I sorgenti di App Inventor possono essere scaricati con il comando:<br />
<div style="background:#eee; border:1px solid #ccc; padding:5px 10px">git clone [https://github.com/mit-cml/appinventor-sources.git https://github.com/mit-cml/appinventor-sources.git]<br/></div><br />
<br/>Per compilare App Inventor, entrare nella directory appinventor-sources/appinventor compilare con il comando:<br />
<div style="background:#eee; border:1px solid #ccc; padding:5px 10px"><code>ant</code><br/></div><br />
Se tutto va bene deve comparire il messaggio "BUILD SUCCESSFUL"<br />
<br />
<br />
<br />
=== Esecuzione App Inventor ===<br />
<br />
App Inventor viene eseguito come applicazione google appengine, risulta conveniente usare come cartella di base la cartella appinventor (es se su Linux si è fatto il git clone sotto opt:&nbsp;/opt/appinventor-sources/appinventor) e lanciare google appengine con il suo percorso completo, es:<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;"><span style="font-family:courier new,courier,monospace;">/opt/appengine-java-sdk-1.9.27/bin/dev_appserver.sh --port=8888 --address=0.0.0.0 appengine/build/war/</span><br/></div><br />
In questo modo possiamo collegarci ad appinventor puntando il browser su [http://indirizzoserver:8888 http://indirizzoserver:8888]. Possiamo scrivere una app, usare il collegamento AI Companion, ma non compilare.<br />
<br />
Per permettere al sistema di compilare le app è necessario lanciare anche il build server, che sta nella cartella buildserver di appinventor (es&nbsp;<span style="line-height: 20.8px;">&nbsp;</span>/opt/appinventor-sources/appinventor/buildserver) con il comando:<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;"><span style="font-family:courier new,courier,monospace;">ant RunLocalBuildServer<br/></span></div>[[Category:AppInventor|A]]</div>
Fpiantini
https://kata.coderdojo.it/wiki/index.php?title=Snake
Snake
2016-01-24T16:37:32Z
<p>Mbert: </p>
<hr />
<div>= [[Category:Javascript|S]]'Snake' - il gioco del serpente =<br />
<br />
Il file 'snake.html' (trovate tutto in [[Media:Snake.zip|Snake.zip]]) realizza il gioco del serpente, passatempo presente su molti telefonini di prima generazione.<br />
<br />
Data la lunghezza del codice ho inserito nello zip anche 6 file intermedi da cui poter partire.<br />
<br />
La parte html ha un titolo, due righe per punteggio e record e l'elemento canvas che consente di disegnare il campo da gioco, serpente e cibo.<br />
<br />
Il codice inizia con la definizione delle variabili, una serie di funzioni, la gestione dei tasti freccia e la chiamata alla funzione 'init' che crea il serpente, il cibo ed il loop del gioco.<br />
<br />
Il serpente è un array, ogni elemento rappresente una cella del serpente. Quando il serpente si muove una nuova testa viene aggiunta al serpente e la coda, l'ultimo elemento del serpente viene eliminata. In questo modo si ottiene il movimento del serpente guidato dai tasti. La funzione 'scena' decide la nuova posizione della testa e verifica le condizioni di gioco: il serpente esce dal campo, il serpente si mangia. Quando la nuova testa è sul cibo il punteggio viene incrementato e creato un nuovo cibo.<br />
<br />
= Possibili varianti =<br />
<br />
Inserire degli ostacoli.<br />
<br />
Creare più cibo.<br />
<br />
Creare dei tunnel o porte comunicanti (come suggerito da un ninja).</div>
Mbert
https://kata.coderdojo.it/wiki/index.php?title=Grafico
Grafico
2016-01-24T14:09:49Z
<p>Mbert: </p>
<hr />
<div>= Disegnare un grafico in una pagina HTML =<br />
<br />
Il file Grafico.html (trovate tutto in [[Media:Grafico.zip|Grafico.zip]]) contiene la parte html e javascript necessarie per visualizzare il grafico di una funzione matematica ''y = f(x)'', naturalmente questa funzione deve essere inserita come funzione javascript con un parametro, ovvero la variabile ''x'' ed un valore di ritorno che contiene il valore ''y di f(x)''. Ponete attenzione al valore di ritorno: deve essere un numero; a parte questo la funzione non ha altre restrizioni.<br />
<br />
La parte html ha un titolo e l'elemento che consente di disegnare il grafico, un tag canvas con 'id' e dimensioni desiderate.<br />
<pre><!DOCTYPE html><br />
<html><br />
<head><br />
<meta charset="utf-8"><br />
<title>Grafici</title><br />
<style><br />
.container {<br />
width: 700px;<br />
margin-left: auto;<br />
margin-right: auto;<br />
}<br />
</style><br />
</head><br />
<body><br />
<div class="container"><br />
<center><br />
<h1>Grafico</h1><br />
<br/><br />
<canvas id="grafico" width="640" height="480"></canvas><br />
</center><br />
</div><br />
<script type="text/javascript"><br />
...<br />
</script><br />
</body><br />
</html><br />
</pre><br />
La parte javascript contiene 4 funzioni utilizzabili come esempi di ''y = f(x)''.<br />
<pre>// Esempi di funzione<br />
function fun1(x) {return Math.sin(x); }<br />
function fun2(x) {return Math.cos(3*x);}<br />
function fun3(x) {return fun1(x) * fun2(5*x);}<br />
function fun4(x) {return fun1(x*x) * fun2(x);}<br />
<br />
//Inizializzazione Canvas<br />
var canvas = document.getElementById('grafico'),<br />
ctx = canvas.getContext("2d"),<br />
graph = {},<br />
axes = {};<br />
</pre><br />
<br/>Nella parte di definizione delle variabili il tag canvas viene inserito in una variabile e recuperato il suo contesto bidimensionale. In Html il canvas è un oggetto complesso, cioé contenente molti metodi per disegnare, sia in 2D che in 3D, questi metodi sono esposti nel contesto ottenuto con ''getContext''.<br />
<br />
Seguono le due funzioni che disegnano gli assi ed il grafico vero e proprio.<br />
<br />
La funzione 'funGraph' prende 3 parametri il primo è la funzione da disegnare, seguono il colore e lo spessore della linea utilizzata.<br />
<br />
<br />
<pre>function funGraph (func,color,thick) {<br />
var dx = graph.step || 4;<br />
var iMax = Math.round((ctx.canvas.width - axes.x0)/dx);<br />
var iMin = graph.drawNegative&nbsp;? Math.round(-axes.x0/dx)&nbsp;: 0;<br />
<br />
graph.scaleX = graph.scaleX || 40;<br />
graph.scaleY = graph.scaleY || graph.scaleX || 40;<br />
ctx.beginPath();<br />
ctx.lineWidth = thick;<br />
ctx.strokeStyle = color;<br />
<br />
for (var i=iMin;i<=iMax;i++) {<br />
var x = dx*i;<br />
var y = graph.scaleY*func(x/graph.scaleX);<br />
if (i==iMin)<br />
ctx.moveTo(axes.x0 + x, axes.y0 - y);<br />
else<br />
ctx.lineTo(axes.x0 + x, axes.y0 - y);<br />
}<br />
ctx.stroke();<br />
};<br />
<br />
function showAxes() {<br />
var xmin = graph.drawNegative&nbsp;? 0&nbsp;: axes.x0;<br />
<br />
ctx.beginPath();<br />
ctx.strokeStyle = "rgb(128,128,128)";<br />
// X axis<br />
ctx.moveTo(xmin, axes.y0);<br />
ctx.lineTo(ctx.canvas.width, axes.y0);<br />
// Y axis<br />
ctx.moveTo(axes.x0, 0);<br />
ctx.lineTo(axes.x0, ctx.canvas.height);<br />
ctx.stroke();<br />
};<br />
</pre><br />
La parte che segue disegna lo sfondo ed il contorno del grafico ed inizializza la posizione degli assi, la scala del grafico e la definizione cioè il numero di pixel usati ad ogni passo della variabile x.<br />
<br />
Infine chiama le funzioni precedenti per disegnare gli assi e due delle funzioni di esempio.<br />
<br />
<br />
<pre> // Preparo il grafico<br />
graph.scaleX = 50; // 50 pixels from x=0 to x=1<br />
graph.scaleY = 80; // 80 pixels from y=0 to y=1<br />
graph.step = 2; // 2 pixels step<br />
graph.drawNegative = true;<br />
<br />
// Coloriamo lo sfondo<br />
ctx.fillStyle = "lightgreen";<br />
ctx.fillRect(0, 0, canvas.width, canvas.height);<br />
// Disegniamo il bordo<br />
ctx.strokeStyle = "black";<br />
ctx.strokeRect(0, 0, canvas.width, canvas.height);<br />
<br />
// Preparo gli assi<br />
axes.x0 = (canvas.width + 1.) / 2;<br />
axes.y0 = (canvas.height + 1.) / 2;<br />
<br />
// visualizzo assi cartesiani<br />
showAxes();<br />
// disegno funzioni<br />
funGraph(fun1,"rgb(11,153,11)",1); <br />
funGraph(fun3,"rgb(66,44,255)",2);<br />
</pre><br />
<br />
<br />
== Evoluzione ==<br />
<br />
Il file grafico2.html contiene una evoluzione del precedente.<br />
<br />
Contiene sostanzialmente lo stesso codice, ma inserito in un oggetto che espone 3 metodi. Riscritto in questo modo l'oggetto, inserito nella variabile 'grafico', rende possibile la creazione di più grafici nella stessa pagina.<br />
<br />
Il metodo 'attach' da chiamare per primo, associa un tag canvas al grafico e opzionalmente mdifica le variabili di disegno.<br />
<br />
Il metodo 'drawAxes' disegna gli assi.<br />
<br />
E naturalmente il metodo 'drawGraph' disegna la funzione passata.<br />
[[Category:Javascript|G]]</div>
Mbert
https://kata.coderdojo.it/wiki/index.php?title=Tutorial:_Breakout
Tutorial: Breakout
2015-11-15T21:17:12Z
<p>Fpiantini: </p>
<hr />
<div>= Coderdojo Firenze -- Tutorial Breakout =<br />
<br />
'''NOTA BENE: Una [http://kata.coderdojo.it/archivio/breakout/TutorialBreakout.pdf versione PDF] e il [http://kata.coderdojo.it/archivio/breakout/Breakout.sb2 codice Scratch] del presente tutorial possono essere scaricate dall'area delle risorse del Coderdojo di Firenze.'''<br />
<br />
[[File:Ctb001.png|Image:ctb001.png]]<br />
<br />
Scopo del gioco è demolire il muro di mattoni nella parte alta dello schermo utilizzando la pallina rimbalzante. Tutte le volte che la pallina tocca un mattone questo viene demolito e scompare. Quando tutti i mattoni sono scomparsi hai vinto.<br />
<br />
Se la pallina tocca la parte bassa dello schermo questa viene persa. Ci sono più palline, quanto tutte vengono perse, il gioco termina.<br />
<br />
Per evitare che la pallina arrivi in fondo allo schermo, essa deve essere rinviata verso l’alto utilizzando una racchetta. La racchetta viene controllata dal giocatore utilizzando, per esempio, i tasti freccia destra e sinistra, oppure il puntatore del mouse.<br />
<br />
== La pallina: movimento nell’area di gioco ==<br />
<br />
Iniziare un nuovo progetto ed eliminare lo sprite del gatto Scratch che per questo gioco non serve.<br />
<br />
<br/>[[File:Ctb002.png|thumb|left]] Creare un nuovo sprite, scegliendo dalla libreria una pallina, per esempio la “Beachball”. Cambiargli il nome in “'''Pallina'''”. Scrivere uno script che fa muovere la pallina a velocità costante all’interno del campo di gioco. Fare in modo che tutte le volte che si riavvia il programma, la pallina parta da una posizione all’interno dello schermo che abbia come x un valore a caso tra tutti quelli possibili e come y il valore 0. Con questa scelta tutte le volte che il gioco inizia la pallina si troverà in un punto a caso della linea orizzontale che attraversa il centro dell’area di gioco (vedi figura).<br />
<br />
<br />
<br />
[[File:Ctb003.png|Image:ctb003.png]]<br />
<br />
<br/>Fare in modo che la pallina si muova in una direzione a caso verso il basso. Per impostare la direzione, ricordarsi di come si misurano gli angoli nello stage di gioco. Fare riferimento alla figura sotto; in particolare notare come gli angoli si possano misurare in due modi: da 0 a 360 gradi girando in senso orario e da -180 a 180 passando per lo zero (che indica sempre la direzione verso l’alto).<br />
<br />
[[File:Ctb004.png|Image:ctb004.png]]<br />
<br />
<br/>Per evitare che la pallina sia troppo grossa, ridurre inoltre la dimensione utilizzando il blocco “porta dimensione al NN%”. Nel caso della BeachBall portare la sua dimensione al 20%. Ultima cosa: la pallina deve rimbalzare quando tocca il bordo. Il programma risultante è riportato sotto.<br />
<br />
[[File:Ctb005.png|Image:ctb005.png]]<br />
<br />
== La pallina: come farla scomparire e far terminare il programma se tocca la parte bassa dello schermo? ==<br />
<br />
Per realizzare questo esistono vari modi, oggi proveremo quello della “'''zona Mangia Palle'''”.<br />
<br />
Definiamo un nuovo sprite, di nome “'''ZonaMangiaPalle'''” costituito da una semplice linea orizzontale di colore giallo che attraversa tutto lo schermo e collochiamolo nella parte bassa dello schermo.<br />
<br />
'''''Tip 1:''' per fare in modo che la linea venga perfettamente orizzontale, mentre si disegna tenere premuto il tasto “Maiuscolo” (o Shift).''<br />
<br />
'''''Tip 2:''' ricordarsi centrare lo sprite in modo preciso.''<br />
<br />
Fare in modo che all’avvio che questo sprite si collochi nella parte bassa del campo di gioco tramite lo script mostrato a lato.<br />
<br />
[[File:Ctb006.png|Image:ctb006.png]]<br />
<br />
A questo punto aggiungere allo Sprite '''Pallina''' lo script sotto:<br />
<br />
[[File:Ctb007.png|Image:ctb007.png]]<br />
<br />
<br/>Dopo questa modifica il gioco risulterà estremamente corto! Infatti all’avvio del gioco Pallina partirà diretta verso il basso e come dopo pochi secondi toccherà '''ZonaMangiaPalle''' scomparirà dando termine al gioco. '''Dobbiamo trovare il modo di controllare la palllina in modo da reinviarla verso l’alto!'''<br />
<br />
== La racchetta: rispedire la pallina verso l’alto ==<br />
<br />
Per far durare il gioco di più costruiamo un nuovo Sprite chiamato “'''Racchetta'''” che altro non è che un rettangolo nero che si può spostare solo in orizzontale nella zona immediatamente sopra la zona mangia palle.<br />
<br />
'''''Tip 3:''' definire lo stile di rotazione dello Sprite di tipo “solo orizzontale”.''<br />
<br />
Per far muovere la racchetta si possono utilizzare diversi metodi, tra cui:<br />
<br />
*utilizzare i tasti freccia sinistra e destra<br />
*seguire la posizione del mouse<br />
<br />
Qui sotto viene riportato il programma da realizzare per ciascuno dei due casi<br />
<br />
[[File:Ctb008.png|Image:ctb008.png]]<br />
<br />
<br/>A questo punto rimane da aggiungere a '''Pallina '''il codice per farla rimbalzare quando tocca '''Racchetta'''.<br />
<br />
'''''ATTENZIONE:''' questa è la vera parte complicata di questo tutorial. L’algoritmo che implementa il rimbalzo è particolarmente complicato. Se siete dei veri '''Ninja''' provate a farlo da solo. Se non ci riuscite trovate la risposta nella prossima pagina.''<br />
<br />
Vista la sua complessità l’algoritmo di “rimbalzo” merita di essere contenuto all’interno di un blocco dedicato, realizzato tramite il sistema degli “'''Altri Blocchi'''”. Per fare questo andare nella sezione “Altri blocchi” e cliccare sul tasto “'''Crea un blocco'''”.<br />
<br />
[[File:Ctb009.png|Image:ctb009.png]]<br />
<br />
<br/><br/>Dare al blocco il nome “'''RIMBALZA'''”, quindi scrivere il codice da eseguire sotto il “cappello viola” con nome “definisci RIMBALZA” (vedi sotto a destra). Adesso tutte le volte che vorremo far rimbalzare la pallina basterà utilizzare il nuovo blocco “RIMBALZA”.<br />
<br />
[[File:Ctb010.png|Image:ctb010.png]]<br />
<br />
A questo punto è possibile divertirsi a far rimbalzare la pallina verso l’alto in modo da non farla cadere nella “'''Zona Mangia Palle'''”.<br />
<br />
[[File:Ctb011.png|Image:ctb011.png]]<br />
<br />
== Il muro da abbattere ==<br />
<br />
Adesso passiamo alla costruzione del muro da abbattere con la pallina. Come sappiamo, il muro è formato da mattoni. Costruiamo quindi un nuovo sprite chiamato “'''Mattone'''”, che altro non è che un rettangolo di colore più o meno marrone. Aiutarsi con la “grid” e fare più o meno un rettangolo delle dimensioni in figura.<br />
<br />
[[File:Ctbmattone.png|Image:ctbmattone.png]]<br />
<br />
<br/>Per costruire il muro occorrono molti mattoni. Per evitare di dover definire molti sprite utilizzeremo la funzione di “'''Clonazione'''”.<br />
<br />
Ricordiamoci inoltre che il muro deve occupare solo la parte superiore dello Stage (y > 0).<br />
<br />
Ecco quindi un esempio di script per generare il muro. E’ abbastanza complesso, vanno definite tre variabili ('''numero_mattoni''', '''indice''' e '''riga''') e i numeri presenti nell’algoritmo potrebbero dover essere adattati in base alla dimensione del mattone, in modo da generare il muro più regolare e compatto possibile. A voi, come esercizio, capire come funziona...<br />
<br />
[[File:Ctb012.png|Image:ctb012.png]]<br />
<br />
<br/>'''N.B.''' A seconda della dimensione del mattone, può darsi che i numeri contenuti nell’istruzione “'''vai a'''” debbano essere modificati un poco. Cercate rendere il muro il più possibile regolare in modo che non rimanga troppo spazio tra i mattoni.<br />
<br />
Da notare poi l’istruzione '''invia a tutti il segnale “Inizio”''' che appare nello script principale alla fine delle operazioni di clonazione. Capiremo più tardi a cosa serve questa istruzione.<br />
<br />
Nella figura che segue si vede come dovrebbe apparire a questo punto il campo di gioco<br />
<br />
[[File:Ctb013.png|Image:ctb013.png]]<br />
<br />
'''''PROBLEMA. '''Si noti come la procedura di creazione del muro con tutte le operazioni di clonazione duri diversi secondi e come durante questa fase la pallina sia già in moto. Questo risulta piuttosto fastidioso. Sarebbe meglio che durante la fase di costruzione del muro il gioco sia ancora fermo e che la pallina cominci a muoversi solo nel momento che il muro è terminato.''<br />
<br />
Come fare? Prima di proseguire con la lettura, pensateci e provate a risolvere il problema.<br />
<br />
'''SOLUZIONE: '''''utilizzare il segnale “'''Inizio'''” inviato dal mattone una volta terminate le operazioni di clonazione''. Nello script che governa il movimento della pallina (quello visto a pagina 4)<br />
<br />
sostituire il blocco:<br />
<br />
[[File:Ctb014.png|Image:ctb014.png]]<br />
<br />
con il blocco<br />
<br />
[[File:Ctb015.png|Image:ctb015.png]]<br />
<br />
Allo Sprite '''Pallina''' va poi aggiunto un miniblocco che all’avvio lo nasconda:<br />
<br />
[[File:Ctb016.png|Image:ctb016.png]]<br />
<br />
== Distruggere il muro! ==<br />
<br />
A questo punto occorre realizzare l’interazione tra muro e pallina.<br />
<br />
Cosa succede a una palla quando colpisce il muro? Rimbalza! Al programma di '''Pallina''' è quindi necessario aggiungere il seguente Script:<br />
<br />
[[File:Ctb017.png|Image:ctb017.png]]<br />
<br />
<br/>'''N.B. '''Notare come aver definito l’algoritmo di rimbalzo tramite un nuovo blocco, ci permetta adesso di utilizzarlo in modo semplice<br />
<br />
Nel nostro gioco succede poi un’altra cosa: quando la pallina colpisce un mattone, il mattone viene distrutto. Questo si ottiene tramite il seguente script da aggiungere allo Sprite '''Mattone'''.<br />
<br />
[[File:Ctb018.png|Image:ctb018.png]]<br />
<br />
== Migliorie ==<br />
<br />
=== Ritardare la partenza della pallina ===<br />
<br />
Appena finito di costruire il muro '''Pallina''' compare immediatamente in una posizione causale e parte verso una direzione causale. Per dare tempo al giocatore di posizionare '''Racchetta''' sotto la pallina e prepararsi a prenderla, aggiungere il seguente pezzo di codice allo Script di avvio della pallina:<br />
<br />
[[File:Ctb019.png|Image:ctb019.png]]<br />
<br />
=== Aumentare il numero di palline a disposizione del giocatore ===<br />
<br />
Fare questo comporta una modifica agli script di '''Pallina'''.<br />
<br />
In particolare introdurre una nuova variabile di nome “'''numero_palline'''” e modificare gli script visti a pagina 3 nel seguente modo:<br />
<br />
[[File:Ctb020.png|Image:ctb020.png]]<br />
<br />
=== ===<br />
<br />
=== Inserire le schermate di fine gioco ===<br />
<br />
[[File:Ctb021.png|Image:ctb021.png]]<br />
<br />
Definire uno Sprite con una scritta di “'''Livello Terminato'''” che appaia alla fine della partita in caso di successo, cioè quando tutti i mattoni sono stati distrutti (la variabile '''numero_mattoni''' arriva a zero).<br />
<br />
[[File:Ctb022.png|Image:ctb022.png]]<br/><br/>Definire uno Sprite di “'''Game Over'''” che appare quando la missione fallisce, cioè le palline finiscono e sono presenti ancora mattoni.<br />
<br />
[[File:Ctb023.png|Image:ctb023.png]]<br />
<br />
[[File:Ctb024.png|Image:ctb024.png]]<br />
<br />
=== Migliorie lasciate come esercizio ===<br />
<br />
==== Inserire il calcolo di un punteggio ====<br />
<br />
==== Aumentare la velocità della pallina con il passare del tempo ====<br />
<br />
==== Ridurre la dimensione della racchetta ====<br />
<br />
(la dimensione della racchetta potrebbe essere ridotta semplicemente con il passare del tempo o quando colpisce qualche “mattone speciale”)<br />
<br />
==== Inserire altri schemi di muro ====<br />
<br />
(una volta terminato un livello invece di terminare il gioco creare nuovi muri cambiando la formula della creazione del muro vista a pagina 6)<br />
<br />
==== Aggiungere suoni ====<br />
<br />
Per esempio aggiungere suoni quando '''Pallina''' rimbalza su '''Racchetta''', sui bordi o sui mattoni.<br />
<br />
==== Complicare l’algoritmo di rimbalzo di Pallina ====<br />
<br />
Questa è probabilmente la cosa più interessante (nonché più complicata e quindi divertente…) di tutte. Alcuni spunti:<br />
<br />
*Se la pallina colpisce uno spigolo dovrebbe rimbalzare in modo diverso? Come?<br />
*Se la pallina colpisce la racchetta in movimento dovrebbe prendere un “effetto” e rimbalzare in modo diverso… Come cambia la formula del rimbalzo?<br />
*E’ possibile che il modo con cui si colpisce la pallina oltre al cambio di direzione comporti anche un cambio di velocità? Come cambia l’algoritmo del rimbalzo?<br />
*Altro??<br />
<br />
[[File:Ctb025.png|Image:ctb025.png]]<br />
<br />
== Appendice (per i pigri): tutti gli script ==<br />
<br />
=== PALLINA ===<br />
<br />
[[File:Ctb026.png|Image:ctb026.png]]<br />
<br />
=== ZONA MANGIA PALLE ===<br />
<br />
[[File:Ctb027.png|Image:ctb027.png]]<br />
<br />
=== RACCHETTA ===<br />
<br />
[[File:Ctb028.png|Image:ctb028.png]]<br />
<br />
=== MATTONE ===<br />
<br />
[[File:Ctb029.png|Image:ctb029.png]]<br />
<br />
=== LIVELLO TERMINATO ===<br />
<br />
[[File:Ctb030.png|Image:ctb030.png]]<br />
<br />
=== GAME OVER ===<br />
<br />
[[File:Ctb031.png|Image:ctb031.png]]<br />
[[Category:Pagine che includono file inesistenti|Category:Pagine che includono file inesistenti]]<br/>[[Category:Scratch|B]]</div>
Fpiantini
https://kata.coderdojo.it/wiki/index.php?title=Tutorial:_Fantasma_Acchiappadolcetti_remix
Tutorial: Fantasma Acchiappadolcetti remix
2015-11-10T11:57:22Z
<p>Giulia: </p>
<hr />
<div>= Tutoria: Fantasma Acchiappa Dolcetti (remix) =<br />
<br />
== Scopo del gioco ==<br />
<br />
Entro un tempo prestabilito, bisogna far entrare nel sacchetto del fantasma i dolcetti che cadono dall’alto verso il basso e fanno guadagnare punti, ma bisogna evitare i pipistrelli che, se toccano il fantasma, tolgono punti.<br/>Il fantasma si muove orizzontalmente e verticalmente quando si azionano le fracce destra, sinistra, su e giù.<br />
<br />
== Cosa ci serve? ==<br />
<br />
*3 sprite:<br />
**Dolcetti<br />
**Fantasma<br />
**Pipistrelli<br />
*1 o più Sfondi<br />
<br />
=== Sprite ===<br />
<br />
Gli sprite sono i personaggi, gli animali e gli oggetti ai quali vogliamo far fare delle azioni, dei movimenti.<br/>Devono avere dei comportamenti.<br />
<br />
==== Dolcetti ====<br />
<br />
Iniziare un nuovo progetto: salvarlo con un nome.<br/>Cancellare il gattino che non ci serve.<br/>Trovare il tipo di dolcetto. Si può prendere uno sprite dalla libreria esistente oppure disegnarlo.<br />
<br />
:per es. possiamo scegliere '''Donut'''<br />
<br />
Cosa deve fare?<br/>Quando inizia il gioco il dolcetto deve apparire in alto e cominciare a scendere.<br />
<br />
<br/>[[File:Donut 1.png|Donut_1.png]]Il gioco <u>inizia</u> quando si avvia il programma premendo <u>la bandiera verde</u>, quindi perché il nostro dolcetto cominci a fare qualcosa mettiamo <u>un'istruzione</u> per quando si clicca sulla bandiera verde.<br/>All’inizio non si vede, quindi deve essere <u>nascosto</u> fino a quando non è pronto perché deve avere la <u>misura giusta</u>, puntare nella <u>direzione</u> che vogliamo e la <u>posizione</u> che abbiamo scelto.<br />
<br />
<br />
<br />
[[File:Donut 2.png|Donut_2.png]]<br />
<br />
<br/>Quindi:<br />
<br />
*per sempre<br />
**inserire una pausa di durata casuale tra l'apparizione di un dolcetto e l'altro;<br />
**dare una <u>posizione</u> (x,y) che deve essere in alto; quindi va bene lasciare una y fissa e impostare una x che può variare;<br />
**ora fare apparire il dolcetto;<br />
**a questo punto dare istruzioni per il movimento: ripetere 5 passi finché<br />
***o arriva al bordo inferiore (y < -170)<br />
***oppure tocca il colore del sacchetto. In questo caso deve mandare un messaggio (per cambiare il punteggio).<br />
**Facciamolo sparire.<br />
<br />
<br />
<br />
[[File:Donut 3.png|Donut_3.png]]<br />
<br />
<br />
<br />
==== Fantasma ====<br />
<br />
Il fantasma possiamo disegnarlo oppure prenderlo dalla libreria.&nbsp;<br/>In ogni caso dobbiamo disegnare il contenitore per i dolcetti, che deve avere la parte superiore colorata uniformemente di una tonalità non utilizzata in nessun’altra parte del gioco. Sarà questa che identificherà la condizione per entrare in contatto con i dolcetti.<br />
<br />
<br/>[[File:Ghost 1.png|Ghost_1.png]]<br />
<br />
<br/><br/>Anche il fantasma si azione alla <u>pressione della bandiera verde</u>.<br/>All’inizio non si vede, quindi deve essere nascosto fino a quando sarà pronto ("nascondi").<br/>Dobbiamo definire la <u>posizione</u> di partenza ("x=0"; "y=-50").<br/>In questo caso non si deve definire la direzione verso la quale si deve muovere perché lo muove il giocatore.<br/>Stabiliamo invece quale aspetto deve avere, cioè quale costume.<br/>Finalmente si può mostrare.<br/>Il punteggio lo aggiungiamo dopo.<br />
<br />
<br/>[[File:Ghost 2.png|Ghost_2.png]] Qui abbiamo le istruzioni per farlo muovere.<br/>Inizialmente, possiamo può muoversi anche soltanto orizzontalmente, direzione sinistra destra.<br />
<br />
==== Pipistrelli ====<br />
<br />
<br/>Creare un pipistrello con un suo comportamento.<br/>Poi creare i suoi cloni.<br />
<br />
<br/><br/>All’inizio deve avere:<br />
<br />
*Dimensione<br />
*Posizione<br />
*Direzione<br />
<br />
[[File:Bat 3 bis.png|Bat_3bis.png]]<br />
<br />
Come si deve muovere?<br/>Con cosa deve interagire?<br />
<br />
[[File:Bat 4 bis.png|Movimenti del pipistrello]]<br />
<br />
<span style="line-height: 1.6;">Definiamo questi due comportamenti in due blocchi che ci consentiranno,&nbsp;</span><span style="line-height: 1.6;">successivamente, se vogliamo, di aggiungere altri comportamenti.</span><br />
<br />
Creiamo due Blocchi: Initialize (inizio) e Fly (vola)<br />
<br />
[[File:Bat 2.png|File:Bat 2.png]]<br />
<br />
[[File:Bat 3.png|File:Bat 3.png]]<br />
<br />
<br />
<br />
Completiamo<br/>Per iniziare, quando si clicca la bandiera verde, lo sprite è nascosto.&nbsp;<br/>Poi devo creare il clone di questo sprite, cioè di me stesso, aspettare e ripetere un certo numero di volte questa azione.<br />
<br />
[[File:Bat 1.png|Creazione clone]]<br />
<br />
Ora diamo a tutti i cloni lo stesso comportamento<br />
<br />
[[File:Bat 4.png|Comportamenti dei cloni]]<br />
<br />
=== Sfondi ===<br />
<br />
[[File:Sfondi.png|Blocchi per lo sfondo]]<br />
<br/>[[Category:Pagine che includono file inesistenti|Category:Pagine che includono file inesistenti]]<br/>[[Category:Scratch|Category:Scratch]]</div>
Giulia
https://kata.coderdojo.it/wiki/index.php?title=Tutorial_C%2B%2B_con_le_librerie_Qt_%E2%80%93_Parte_IV
Tutorial C++ con le librerie Qt – Parte IV
2015-01-25T23:32:41Z
<p>Robi: Robi ha spostato la pagina Tutorial C++ con le librerie Qt – Parte IV a Tutorial C++ con Qt - Parte IV: Errore nel nome originario</p>
<hr />
<div>= Tutorial C++ con le librerie Qt – Parte IV =<br />
<br />
= A cosa serve un oggetto =<br />
<br />
Fin dall’inizio del nostro tutorial abbiamo detto che c’erano delle parti del JavaScript che ci sarebbero mancate nel C++, come a esempio gli eventi, e avremmo cercato sostegno in Qt per ritrovarle.<br />
<br />
Un’altra privazione che ci potrebbe dare malinconia sarebbe la scomparsa dei pulsanti, delle caselle di testo e delle immagini. Sembra incredibile che queste tramite HTML e JavaScript siano così facili da gestire e invece nel C++, arrivati alla IV parte del nostro discorso, non se ne sia vista neppure l’ombra. Non saremo mica destinati a proseguire per sempre con una finestrella bianca dove compaiono sole poche righe di testo?<br />
<br />
<br/>No, non siamo destinati, ma non è facile abbandonarla.<br />
<br />
Il C++ non è stato pensato per lavorare all’interno di un browser né per interagire in modo immediato con degli oggetti grafici. Di solito non ci facciamo caso, ma nel nostro computer, anche in questo momento, sono in azione decine di piccoli programmi che noi non vediamo. A seconda del sistema operativo si possono chiamare ''daemons'' o ''services'', ma il nome non cambia la sostanza: sono programmi che compiono operazioni che non hanno bisogno di interagire con l’utente.<br />
<br />
Se non ci avete mai pensato, eccovi qualche esempio: perché quando spostate il mouse il puntatore vi segue sullo schermo? È ovvio che c’è un programma in ascolto che aspetta di ricevere dei segnali dal mouse e, nel momento in cui li riceve, li decifra e adotta dei comportamenti di conseguenza. Lo stesso discorso pari pari si potrebbe fare per la tastiera o per la scheda di rete, come per mille altre cose.<br />
<br />
Il computer è una macchina complessa piena di sensori e il sistema operativo è composto da centinaia di programmi che si prendono cura di tutti queste problematiche. Noi in realtà abbiamo la possibilità di interagire con un numero molto ristretto di programmi, che spesso sono conosciuti come ''applicativi''. Non è detto quindi che a un linguaggio di programmazione sia richiesto di saper gestire con facilità interfacce grafiche come finestre, pulsanti, caselle di testo e quant’altro; anzi, moltissimi linguaggi molto apprezzati vengono usati per scrivere programmi che agiscono sullo sfondo, invisibili all’utente.<br />
<br />
<br/>Il C++ è un buon compromesso fra questi due ‘mondi’: non nasce per gestire interfacce grafiche, ma può riuscirci con grande efficienza, a patto di perderci un po’ di tempo. Noi stiamo per compiere i primi passi in quella direzione perché, se è vero che il concetto di ''oggetto'' in informatica è piuttosto ampio e forse soggetto a diverse interpretazioni, possiamo intanto metterci d’accordo nel dire che finestre, caselle di testo e pulsanti sono degli ''oggetti''.<br />
<br />
In realtà abbiamo già incontrato ''oggetti'' di tipo diverso: vi ricordate che abbiamo detto che una ''string'' è un ''oggetto''? Quindi gli oggetti non sono solo oggetti grafici, ma il vantaggio di parlare degli oggetti grafici è che è molto più facile descrivere le loro caratteristiche.<br />
<br />
<br/>Allora cominciamo a descriverli.<br />
<br />
Una delle caratteristiche più apprezzate di un oggetto è che di solito ha dei ''metodi''. Abbiamo già detto che nel C++ i ''metodi'' non sono altro che funzioni e si scrivono esattamente come tutte le funzioni. La loro caratteristica è che si accompagnano a un determinato oggetto e interagiscono solo con quell’oggetto lì, mentre non possiamo far fare loro altre cose.<br />
<br />
Uscendo dal C++ e parlando in generale, possiamo immaginarci un ''metodo'' come un’azione che un oggetto è in grado di compiere. Facciamo l’esempio di un pulsante. Mettiamo il caso che ci faccia comodo avere un pulsante che, quando riceve il click del mouse, fa comparire una finestra di avviso (a esempio, “Click ricevuto!”).<br />
<br />
Nel JavaScript sappiamo già farlo.<br />
<br />
In un file HTML scriviamo:<br />
<pre><input type="button" value="Fai click per ricevere un avviso" onclick="mostraAvviso()" /></pre><br />
e in un file JavaScript collegato:<br />
<pre>function mostraAvviso() {<br />
alert ("Click ricevuto!");<br />
}</pre><br />
Per un problema così semplice non abbiamo in apparenza nemmeno bisogno di creare un oggetto.<br />
<br />
Ma in realtà non è così: il fatto è che nello HTML ci sono un sacco di ''oggetti'' già pronti all’uso e ''<input type="button"…'' è uno di quelli.<br />
<br />
Il JavaScript a sua volta è in grado di interagire con questi oggetti e ‘integrarli’ aggiungendoci dei metodi, ossia delle azioni che vengono compiute quando l’utente interagisce con l’oggetto.<br />
<br />
<br/>L’esempio di un pulsante grafico è molto immediato e cercheremo quanto prima di replicarlo nel C++, anche se ci vorrà un po’. Per ora cerchiamo di capire questa comodità di un oggetto e del perché siano così ‘di moda’, ossia cosa sia un metodo e perché piaccia così tanto.<br />
<br />
Collegando le funzioni che scriviamo a un determinato oggetto noi siamo in grado di scrivere un codice molto ordinato e comprensibile composto da ''oggetti'' che possono fare determinate cose. A seconda di ciò che vogliamo fare, potremo poi usare un oggetto o un altro.<br />
<br />
Per dire, se vogliamo gestire del testo, possiamo usare un oggetto ''string'', che ci offre metodi per modificarlo, ad esempio operandoci dentro delle sostituzioni, come abbiamo già fatto. Se invece vogliamo gestire un gruppo di dati simili fra di loro possiamo usare un ''vector'', che ci offre degli strumenti come l’indice.<br />
<br />
La prima caratteristica di un ''oggetto'' è quindi che può compiere delle azioni. Queste azioni sono programmate nei metodi, che altro non sono che funzioni con un nome diverso.<br />
<br />
<br/>Adesso cerchiamo di capire cos’è una ''proprietà'' di un ''oggetto''.<br />
<br />
Lo avevamo già anticipato parlando di ''length'': una proprietà non è altro che una variabile (ok, può essere anche qualcos’altro, ma ne parleremo molto più avanti).<br />
<br />
Anche in questo caso stiamo parlando di una variabile che è collegata a un determinato oggetto e non ha senso se non in relazione a esso.<br />
<br />
<br/>Cerchiamo di cogliere l’utilità di questa caratteristica degli oggetti.<br />
<br />
Abbiamo detto un sacco di volte che il C++ è pensato perché un sacco di persone possano lavorare sullo stesso programma senza pestarsi i calli. Però poi abbiamo trovato solo due tipi di variabili: quelle globali, che tutti possono modificare, e quelle locali, che muoiono appena si esce dalla funzione.<br />
<br />
Detta così, parrebbe un mondo molto in bianco e nero in cui si può scegliere solo fra due possibilità: o tutto o niente. O una variabile visibile dappertutto che non muore mai, o una variabile nascostissima nella nostra funzione che ci abbandonerà quanto prima. Un po’ drastico, no?<br />
<br />
È vero che esistono i parametri, i puntatori e i riferimenti, ma l’apparenza è di una grande rigidità.<br />
<br />
<br/>Non farebbe comodo una situazione intermedia? Non so, una variabile che sopravviva alle funzioni, ma non possa essere modificata con facilità da tutti?<br />
<br />
Beh, in effetti ci sono altre possibilità come l’uso della parola magica ''new'', ma è ancora un po’ presto per affrontare questo argomento.<br />
<br />
Però vediamo se gli oggetti ci possono venire in aiuto. Se dichiaro una variabile come ''proprietà'' di un oggetto, quale sarà la vita di quella variabile?<br />
<br />
A questa domanda possiamo già dare una risposta, pur non avendo ancora visto come sono fatti gli oggetti, perché è piuttosto semplice: esattamente la stessa. Se un oggetto è definito in una funzione, muore alla fine della funzione. Se è definito fuori da ogni funzione, sopravvive fino alla fine del programma, ma può essere visto da ogni parte del codice. Le sue ''proprietà'' vivono e muoiono con lui.<br />
<br />
<br/>A prima vista, quindi, non ci è di nessun aiuto, però un oggetto può avere un’altra caratteristica: una variabile può essere nascosta al suo interno ed essere inaccessibile al resto del codice. In pratica diventa una proprietà nascosta dell’oggetto.<br />
<br />
Qual è l’utilità? L’utilità è nelle parole “al resto del codice”. Significa che quella variabile continua a rimanere accessibile a quelle funzioni che '''fanno parte''' dell’oggetto, ossia ai metodi dell’oggetto.<br />
<br />
<br/>In pratica posso creare una variabile e nasconderla dentro un oggetto. Mettiamo che l’oggetto sia globale: tutto il codice può vedere l’oggetto, ma la variabile rimane comunque inaccessibile perché è nascosta lì dentro.<br />
<br />
Poniamo che io abbia bisogno di modificare i dati contenuti in quella variabile. Bene, questo può diventare possibile se scrivo una funzione '''che faccia parte dell’oggetto''', ossia sia un metodo dell’oggetto, che modifica quei dati come voglio io.<br />
<br />
La cosa può sembrare cervellotica, ma ecco la conclusione: questo può capitare solo se io posso accedere al codice dell’oggetto!<br />
<br />
In altre parole: se ho a disposizione il file dove è scritto il codice dell’oggetto, allora posso aggiungere un metodo che mi fa interagire con quella variabile, ossia mi fa modificare i dati contenuti.<br />
<br />
Se invece non ho a disposizione quel file, ''ergo'': il codice l’ha scritto qualcun altro, allora io '''non ho modo''' di andare a rompergli le uova nel paniere; potrò usare quell’oggetto, ma senza accedere ai dati di quella proprietà.<br />
<br />
E lo stesso vale per gli altri: se scrivo un oggetto io e lo dichiaro globale, tutti potranno usarlo. Ma se ho dichiarato nascosta (si dice ''privata'') una delle variabili lì contenute, nessuno potrà accedere ai dati di quella proprietà. La cosa sarà a mia discrezione: se scrivo un metodo che consenta di leggere quei dati, essi potranno essere letti, ma nient’altro; se scrivo un metodo che consenta di modificarli, essi potranno essere modificati. Ma potranno essere modificati come decido io. A esempio, se si trattasse di una variabile ''int'', potrei decidere di consentire solo di incrementare il valore della variabile, ma mai di diminuirlo.<br />
<br />
Potrei addirittura consentire di modificare i dati continuando a impedire che vengano letti.<br />
<br />
<br/>Ho quindi ottenuto ciò che stavo cercando: una variabile globale che non sia facilmente modificabile.<br />
<br />
<br/>Adesso cercheremo di immaginare e poi progettare un oggetto che abbia qualcuna di queste caratteristiche, ossia abbia delle ''proprietà'', dei ''metodi'' e che alcune di queste proprietà siano ''private'', ossia siano inaccessibili dall’esterno e si possano modificare solo tramite dei metodi pensati ad hoc.<br />
<br />
<br />
<br />
= Un robottino in JavaScript =<br />
<br />
Facciamo finta di essere in vacanza su qualche spiaggia tropicale e lì, non avendo nulla da fare, al sole di mezzodì ci punga vaghezza di costruire un piccolo robot. Purtroppo siamo lontani da casa e, rovistando fra i bagagli, vengono fuori solo pinne, boccagli e costumi da bagno: un po’ poco per costruire un robot. A questo punto siamo costretti a fare buon viso a cattivo gioco e a rimandare il nostro progetto.<br />
<br />
Intanto, però, possiamo fantasticare su cosa il nostro piccolo robot dovrebbe saper fare. A questo punto, per passare il tempo ci mettiamo a simulare quel robot sullo schermo del nostro pc per decidere come dovrà funzionare. Non potendolo vedere, ci immaginiamo di avere un telecomando per farlo andare a destra e a sinistra, un sensore che ci dice in che posizione si trova e un indicatore dello stato della batteria.<br />
<br />
<br/>A questo punto siamo pronti a costruire il nostro primo oggetto: un robottino virtuale, che non si vedrà, ma di cui potremo avere sullo schermo del computer alcune informazioni.<br />
<br />
Le azioni che il robottino immaginario potrà compiere saranno andare a destra, a sinistra, in avanti o all’indietro. Queste azioni saranno rappresentate dai metodi.<br />
<br />
Il nome del robottino e la sua posizione saranno invece le sue proprietà.<br />
<br />
<br />
<br />
== L’interfaccia HTML ==<br />
<br />
Questo tutorial si rivolge a chi ha digerito almeno le basi del JavaScript, ma in questo caso il codice che andremo a scrivere sarà un po’ più complicato di quelli che abbiamo buttato giù fino a qui, perciò forse è meglio se proseguiamo passo passo.<br />
<br />
Intanto costruiamo la nostra interfaccia HTML. Per cominciare, vogliamo poter dare un nome al nostro robottino, perciò ci serve una casella di testo in cui scriverlo e un pulsante per dire al JavaScript di venirlo a leggere.<br />
<pre><!DOCTYPE html><br />
<html lang="it"><br />
<head><br />
<meta charset="utf-8"><br />
<br />
<title>Proprietà e metodi privati</title><br />
<br />
<link rel="stylesheet" href="standard.css" /><br />
<script type="text/javascript" src="privati.js"></script><br />
</head><br />
<br />
<body><br />
<div><br />
<header><br />
<h1>Robottino immaginario</h1><br />
</header><br />
<br />
<div><br />
<label>Dai un nome al robottino: </label><br />
<input id="battesimo" type="text" /><br />
<input type="button" value="battezza" onclick="battezza();" /><br />
</div><br />
<br />
<footer><br />
<p>© Copyright by CoderDojo Firenze</p><br />
</footer><br />
</div><br />
</body><br />
</html></pre><br />
Un buon nome per il file precedente può essere “index.html”. Quel che segue è il primo embrione del file “privati.js”:<br />
<pre>function battezza () {<br />
var nome = document.getElementById("battesimo").value;<br />
alert(nome);<br />
}</pre><br />
Beh, la nostra interfaccia verso il robottino è davvero rudimentale, ma non abbiamo fretta.<br />
<br />
Adesso ci vogliamo aggiungere qualche ‘sensore’ e i pulsanti per guidare il robottino.<br />
<br />
Aggiungiamo quindi una casella di testo dove ci verrà confermato il nome che abbiamo scelto per il robot. Sotto ne metteremo un’altra dove potremo leggere la posizione del nostro robottino.<br />
<br />
Scendendo ancora, dovremo posizionare ben quattro pulsanti, con le scritte “sali”, “scendi”, “sinistra” e “destra”, che ci serviranno per ‘guidare’ il nostro robottino.<br />
<br />
Ancora sotto una barra che ci indicherà lo stato di carica del robottino.<br />
<br />
<br/>Per riuscire a tenere in ordine tutti questi pulsanti e caselle dovremmo spendere un sacco di energia con i CSS, perciò violeremo un po’ i sacri principi dello HTML e useremo una tabella, che è un sistema semplice, ma disapprovato, per piazzare le cose in uno schema preciso.<br />
<br />
Ecco il file completo:<br />
<pre><!DOCTYPE html><br />
<html lang="it"><br />
<head><br />
<meta charset="utf-8"><br />
<br />
<title>Proprietà e metodi privati</title><br />
<br />
<link rel="stylesheet" href="standard.css" /><br />
<script type="text/javascript" src="privati.js"></script><br />
</head><br />
<br />
<body><br />
<div><br />
<header><br />
<h1>Membri privati</h1><br />
</header><br />
<br />
<div><br />
<div><br />
<label>Dai un nome al robottino: </label><br />
<input id="battesimo" type="text" /><br />
<input type="button" value="battezza" onclick="battezza();" /><br />
</div><br />
<table class="stacco_2em"><br />
<tr><br />
<th colspan="3" class="bordato">Robottino</th><br />
</tr><br />
<tr><br />
<td>nome</td><br />
<td colspan="2" class="bordato" id="nome">&nbsp;</td><br />
</tr><br />
<tr><br />
<td>posizione</td><br />
<td colspan="2" class="bordato" id="pos">&nbsp;</td><br />
</tr><br />
<tr><br />
<td>&nbsp;</td><br />
<td>&nbsp;</td><br />
<td>&nbsp;</td><br />
</tr><br />
<tr><br />
<td>&nbsp;</td><br />
<td class="centrato"><input type="button" value="sali" onclick="vaiSu();" /></td><br />
<td>&nbsp;</td><br />
</tr><br />
<tr><br />
<td class="centrato"><input type="button" value="sinistra" onclick="vaiSx();" /></td><br />
<td>&nbsp;</td><br />
<td class="centrato"><input type="button" value="destra" onclick="vaiDx();" /></td><br />
</tr><br />
<tr><br />
<td>&nbsp;</td><br />
<td class="centrato"><input type="button" value="scendi" onclick="vaiGiu();" /></td><br />
<td>&nbsp;</td><br />
</tr><br />
<tr><br />
<td>&nbsp;</td><br />
<td>&nbsp;</td><br />
<td>&nbsp;</td><br />
</tr><br />
<tr><br />
<td>Carica</td><br />
<td colspan="2"><progress id="carica" max="100"></progress></td><br />
</tr><br />
</table><br />
</div><br />
<br />
<footer><br />
<p>© Copyright by CoderDojo Firenze</p><br />
</footer><br />
</div><br />
</body><br />
</html></pre><br />
Un sacco di roba, vero?<br />
<br />
Se però non fate caso a tutti i &lt;td&gt; e &lt;tr&gt; della tabella, in realtà ci trovate solo le cose che avevamo elencato prima:<br />
<br />
#i primi due li avevamo già inseriti:<br />
##una casella di testo dove scrivere il nome con cui vogliamo chiamare il robottino;<br />
##un pulsante per farlo leggere al JavaScript;<br />
#poi:<br />
##una casella di testo dove verrà riportato il nome del robottino;<br />
##una casella dove comparirà la sua posizione;<br />
##quattro pulsanti con le scritte: “sali”, “scendi”, “sinistra” e “destra”<br />
##una barra che indica la carica residua.<br />
<br />
Ogni pulsante chiama una differente funzione sul file JavaScript, per cui non ci resta che scriverle.<br />
<br />
<br/>Però… calma! Noi non vogliamo scrivere tante funzioni separate. Vogliamo che siano i metodi di un oggetto ‘robottino’! Sarà possibile farlo?<br />
<br />
A questo punto dobbiamo capire come fa il JavaScript a creare un oggetto... su misura.<br />
<br />
<br/>Il JavaScript è molto flessibile, così tanto che di tecniche per creare oggetti ne sono previste più d’una. Noi sceglieremo quella che ha una qualche somiglianza con il C++: la tecnica della funzione prototipo.<br />
<br />
In pratica per progettare un oggetto con questa tecnica basta scrivere una funzione che contenga tutte le variabili e le funzioni che ci servono: le prime diventeranno le proprietà e le seconde i metodi.<br />
<br />
La differenza maggiore con il C++ è che il JavaScript non prevede un sistema immediato per rendere una variabile inaccessibile dall’esterno. Per ottenere questo risultato dovremmo introdurre il concetto di ''closure''… Secondo me però non conviene mettere troppa carne al fuoco, perciò facciamo così: prima progettiamo un ''oggetto'' che abbia solo proprietà e nessun metodo (sarebbe a dire solo variabili e nessuna funzione). Le funzioni che interagiscono con quelle proprietà, che quindi per ora non saranno private, nasceranno esterne all’oggetto.<br />
<br />
In una seconda fase introdurremo le ''closure'', faremo diventare le funzioni esterne metodi dell’oggetto e renderemo private le proprietà; in questo modo saremo in grado di partire da un codice già conosciuto per introdurne di nuovo.<br />
<br />
<br/>Ci rimboccheremo le maniche fra un secondo, ma intanto vi incollo qui il codice dei CSS che ci aiuteranno a rendere più comprensibile ciò che stiamo facendo. Il file è previsto che si chiami “standard.css”:<br />
<pre>.nascosto {<br />
display: none;<br />
visibility: hidden;<br />
}<br />
<br />
td.bordato {<br />
border: 1px ridge maroon;<br />
border-collapse: collapse;<br />
}<br />
<br />
th, td {<br />
padding: 0.3em;<br />
}<br />
<br />
.stacco_1em {<br />
margin-top: 2em;<br />
}<br />
<br />
.stacco_2em {<br />
margin-top: 1em;<br />
}<br />
<br />
.centrato {<br />
text-align: center;<br />
text-indent: 0;<br />
}</pre><br />
<br />
<br />
== Un robottino senza closure ==<br />
<br />
Visto che stiamo creando un robottino, direi che non sarebbe male chiamare così la funzione che funge da stampo per l’oggetto:<br />
<pre>function Robottino () {</pre><br />
Niente male!<br />
<br />
Adesso rileggiamo l’elenco precedente per decidere quali dati dovrà gestire. Come minimo sono 3:<br />
<br />
#nome<br />
#posizione<br />
#stato della carica<br />
<br />
In realtà però la posizione dovrà essere rappresentata da almeno 2 numeri: uno che dice quanto si è spostato a destra o a sinistra e uno che ci dice di quanto è si è allontanato (= è salito) o si è avvicinato (= è sceso). Chiamiamo “x” il numero che indica sinistra o destra; chiamiamo invece “y” il numero che dice se si è allontanato o avvicinato.<br />
<br />
Facciamo finta che abbiamo posato il nostro robottino al centro di una stanza. Quel punto lì lo chiamiamo 0. Perciò al momento della partenza il robottino si trova in posizione 0.<br />
<br />
Se lo facciamo muovere verso sinistra, allora il numero x deve diminuire.<br />
<br />
Se lo facciamo muovere verso destra, allora x deve crescere.<br />
<br />
Lo stesso discorso lo applichiamo a y: quando il robot si allontana, y sale, mentre quando torna indietro y cala.<br />
<br />
<br/>Abbiamo dunque bisogno di ben 4 proprietà:<br />
<pre>var nome;<br />
var carica;<br />
var x;<br />
var y;</pre><br />
Molto bene, la nostra funzione sta cominciando a prendere forma. A questo punto andiamo sulle cose pratiche: la rima cosa che ci si aspetta che succeda è che venga scritto il nome nella casella di testo con id="battesimo" e poi venga premuto il pulsante “battezza”, il quale a sua volta invoca la funzione battezza()… che però non esiste ancora!<br />
<br />
Allora proviamo a immaginarci anche quella. La funzione dovrà solo recuperare il testo contenuto nella casella di testo ‘battezza’ e inserirlo nella variabile ‘nome’ della funzione ''Robottino()''. L’ostacolo è che in questo momento la variabile ‘nome’ è locale alla funzione ''Robottino()'' e non vi si può accedere dall’esterno. Dovremo quindi fare una piccola modifica a ''Robottino()'' perché accetti almeno un parametro; già che ci siamo, stabiliamo un principio generale: i nostri robottini nasceranno tutti al centro della stanza con il 100% di carica. A questo punto la prima versione della funzione ''Robottino()'' può essere questa:<br />
<pre>function Robottino (pa_nome) {<br />
var nome = pa_nome;<br />
var carica = 100;<br />
var x = 0;<br />
var y = 0;<br />
}</pre><br />
Mentre la prima versione di battezza() può essere:<br />
<pre>function battezza () {<br />
var battesimo = document.getElementById("battesimo").value; <br />
Robottino(battesimo);<br />
}</pre><br />
Fin qui, stiamo scrivendo cose già viste molte volte.<br />
<br />
Andiamo avanti. Nella tabella della pagina web c’è una casella dove deve ricomparire il nome del nostro robottino. Anche questo si potrebbe ottenere in maniera molto semplice dall’interno di battezza:<br />
<pre> var nome = document.getElementById("nome");<br />
nome.innerHTML = battesimo;</pre><br />
Il problema è che siamo diventati un po’ esigenti e questo tipo di codice non ci va più bene; infatti noi abbiamo bisogno di una funzione perché poi faremo in modo che diventi un metodo di Robottino(). Una nuova funzione non sarebbe di per sé in grado di leggere la variabile locale ‘battesimo’ perché essa rimarrà nascosta dentro battezza(). Questa nuova funzione dovrà quindi chiedere a Robottino() quale sia il valore della sua variabile ‘nome’.<br />
<br />
<br/>Mi rendo conto che in questo momento il discorso paia un po’ teorico, però non è difficile. In sostanza ora ci rifiutiamo di usare la variabile ‘battesimo’ di ''battezza()'' perché non abbiamo alcuna garanzia che un domani potremo usarla.<br />
<br />
Quindi possiamo anche mantenere la prima riga perché siamo pigroni e ora non abbiamo voglia di scrivere una nuova funzione solo per scrivere il nome del robottino nella apposita casella della tabella; però dovremo almeno modificare la seconda perché diventi una chiamata a una funzione che recuperi il valore della proprietà ‘nome’ di ''Robottino()''.<br />
<br />
Solo che non è assolutamente facile scriverla senza le ''closure''. Sono quindi costretto a una simulazione: rendiamo ‘nome’ di ''Robottino()'' globale in modo che possiamo accedervi da qualsiasi parte del codice.<br />
<br />
Con questo trucchetto possiamo scrivere una ‘finta’ funzione ''getNome()'' che restituisce il valore della variabile ‘nome’ – quando avremo parlato delle ''closure'', trasformeremo ''getNome()'' in una ‘vera’ funzione membro di ''Robottino()'', ossia un metodo di ''Robottino()''. Eccola qua:<br />
<pre>function getNome() {<br />
return nome;<br />
}</pre><br />
Siamo purtroppo costretti a modificare la nostra funzione Robottino() in modo che le proprietà siano tutte globali. Poi rimetteremo tutto a posto:<br />
<pre>function Robottino (pa_nome) {<br />
nome = pa_nome;<br />
carica = 100;<br />
x = 0;<br />
y = 0;<br />
}</pre><br />
A questo punto all’interno di battezza() non potremo più usare ‘nome’ come identificativo di variabile. Usiamo ‘htmlNome’:<br />
<pre>function battezza () {<br />
var battesimo = document.getElementById("battesimo").value; <br />
Robottino(battesimo);<br />
<br />
var htmlNome = document.getElementById("nome");<br />
htmlNome.innerHTML = getNome();<br />
}</pre><br />
Il passaggio successivo consiste nell’inserire il valore corretto nella casella id="pos".<br />
<br />
Il valore corretto è un testo che dica qualcosa di simile:<br />
<pre>x = 0, y = 0</pre><br />
I valori non dovranno rimanere sempre 0, ovviamente: varieranno via via che il robottino si sposterà. Potendo accedere alle variabili ‘x’ e ‘y’, rimane solo da aggiungere il codice per comporre il testo da visualizzare: "x = " + x + ", y = " + y.<br />
<br />
Ecco qui la nostra rivoluzionaria funzione:<br />
<pre>function scriviPosizione() {<br />
scriviPos = document.getElementById("pos");<br />
scriviPos.innerHTML = "x = " + x + ", y = " + y;<br />
}</pre><br />
Abbiamo poi quattro pulsanti che dovrebbero, in maniera un po’ immaginosa, corrispondere ai quattro tasti di un telecomando che farebbe spostare il robottino. La nuova posizione apparirà sul nostro display virtuale nel campo aggiornato dalla funzione precedente.<br />
<br />
In realtà, visto che il robottino non esiste, l’unico effetto che dobbiamo gestire è l’aggiornamento delle variabili ‘x’ e ‘y’.<br />
<pre>function vaiSu() {<br />
y += 1;<br />
scriviPosizione();<br />
scriviCarica(5);<br />
}<br />
<br />
function vaiGiu() {<br />
y -= 1;<br />
scriviPosizione();<br />
scriviCarica(5);<br />
}<br />
<br />
function vaiDx() {<br />
x += 1;<br />
scriviPosizione();<br />
scriviCarica(5);<br />
}<br />
<br />
function vaiSx() {<br />
x -= 1;<br />
scriviPosizione();<br />
scriviCarica(5);<br />
}</pre><br />
Il codice precedente ci costringe a scrivere in maniera un po’ diversa la funzione che fa apparire l’indicatore della carica residua. In pratica si parte dal presupposto che la si invochi perché c’è stata una variazione nella carica, perciò l’entità di tale variazione è stabilita da un parametro.<br />
<br />
Si potrebbe quindi arrivare a qualcosa del genere:<br />
<pre>function scriviCarica(variazione) {<br />
var scriviCar = document.getElementById("carica");<br />
carica -= variazione; <br />
scriviCar.value = carica;<br />
}</pre><br />
Ho scritto due esempi che seguono due logiche diverse per far vedere che la creazione degli oggetti non modifica di per sé come si scrive il codice, ma possiamo continuare a vedere le cose da diverse angolazioni come facevamo prima.<br />
<br />
Le funzioni che spostano il robottino immaginario sanno di avere accesso direttamente alle variabili ‘x’ e ‘y’ e le modificano senza farsi problemi; però non toccano la variabile ‘carica’, che sarebbe sempre nel loro spazio di visibilità. Preferiscono passare un parametro alla funzione ''scriviCarica()'' perché la modifichi lei.<br />
<br />
Se non è chiaro, quel che intendo dire è che le funzioni avrebbero potuto essere scritte anche così:<br />
<pre>…<br />
function vaiSx() {<br />
x -= 1;<br />
carica -= 5;<br />
scriviPosizione();<br />
scriviCarica();<br />
}<br />
<br />
function scriviCarica() {<br />
var scriviCar = document.getElementById("carica");<br />
scriviCar.value = carica;<br />
}</pre><br />
e avrebbero funzionato lo stesso.<br />
<br />
In realtà nessuna delle due strategie sarebbe la migliore nel momento in cui si intende lavorare con gli oggetti. Anche nel JavaScript avremmo potuto fare di meglio, ma ci lasceremo questo tema per quel brontolone del C++ perché in fondo è lui il protagonista di questo tutorial.<br />
<br />
<br/>Per i soliti pigroni che sanno fare solo il copia-incolla, la prima versione senza ''closure'' del nostro robottino è la seguente:<br />
<pre>function battezza () {<br />
var battesimo = document.getElementById("battesimo").value; <br />
Robottino(battesimo);<br />
<br />
var htmlNome = document.getElementById("nome");<br />
htmlNome.innerHTML = getNome();<br />
scriviPosizione();<br />
scriviCarica(0);<br />
}<br />
<br />
function Robottino (pa_nome) {<br />
nome = pa_nome;<br />
carica = 100;<br />
x = 0;<br />
y = 0;<br />
}<br />
<br />
function getNome() {<br />
return nome;<br />
}<br />
<br />
function scriviPosizione() {<br />
scriviPos = document.getElementById("pos");<br />
scriviPos.innerHTML = "x = " + x + ", y = " + y;<br />
}<br />
<br />
function vaiSu() {<br />
y += 1;<br />
scriviPosizione();<br />
scriviCarica(5);<br />
}<br />
<br />
function vaiGiu() {<br />
y -= 1;<br />
scriviPosizione();<br />
scriviCarica(5);<br />
}<br />
<br />
function vaiDx() {<br />
x += 1;<br />
scriviPosizione();<br />
scriviCarica(5);<br />
}<br />
<br />
function vaiSx() {<br />
x -= 1;<br />
scriviPosizione();<br />
scriviCarica(5);<br />
}<br />
<br />
function scriviCarica(variazione) {<br />
var scriviCar = document.getElementById("carica");<br />
carica -= variazione;<br />
scriviCar.value = carica;<br />
}</pre><br />
<br />
<br />
== Introduzione alle closure del JavaScript ==<br />
<br />
Prima di procedere con la lettura, cercate di essere sicuri di aver ben chiaro il codice precedente perché è da quello che partiremo.<br />
<br />
<br/>Abbiamo detto che il metodo che usa il JS per rendere privati i membri di un oggetto (ossia le proprietà e i metodi) è un po’ complicato e si basa sul meccanismo delle ''closure''. Poiché il JS non è l’oggetto di questo tutorial, ci limiteremo a dare una rapida occhiata senza scendere nei dettagli. Uno degli argomenti che ci spinge a questa scelta è che su questo singolo aspetto (rendere privati i membri di un oggetto) il C++ è più semplice e immediato del JS, pertanto non abbiamo motivi di sviscerare a fondo l’argomento.<br />
<br />
<br/>Intanto ci serve una definizione di ''closure''. Prendiamo quella che troviamo sul sito [http://www.w3schools.com http://www.w3schools.com]:<br />
<br />
<br/>A closure is a function having access to the parent scope, even after the parent function has closed.<br />
<br />
<br/>e cerchiamo di tradurla:<br />
<br />
<br/>una ''closure'' è una funzione che può accedere allo spazio di visibilità del suo genitore, perfino dopo che la funzione genitore è terminata.<br />
<br />
<br/>Può darsi che qualcuno ancora non sappia che cos’è una funzione genitore, perciò procediamo con calma.<br />
<br />
Nel C++ abbiamo visto che è possibile assegnare una funzione a un puntatore. Questo è sensato perché la funzione è un blocco di codice che risiede in memoria, pertanto ha un indirizzo e quell’indirizzo può benissimo essere tenuto di mira da un puntatore.<br />
<br />
Abbiamo anche detto più di una volta che la relazione fra ''references'' e puntatori è stretta, tant’è che possiamo considerare i riferimenti come ''pointer'' sottodimensionati.<br />
<br />
Invece ci siamo accorti che il JS cerca di sollevarci dalla maggior parte dei problemi decidendo lui quand’è che deve trattare una variabile come riferimento o no; vi ricordate che quando cercate di copiare un oggetto, in realtà state creando un nuovo riferimento allo stesso oggetto? Se non ve ne ricordate, prima di proseguire tornate al tutorial precedente e rileggete la parte “Differenze fra C++ e JavaScript: i references”.<br />
<br />
A questo punto, c’è qualcuno che si sorprende se scopre che il JS decide in maniera autonoma quando trattare una variabile come fosse un puntatore?&nbsp;:-)<br />
<br />
Guardate un po’ questo codice:<br />
<pre>var sembroUnPuntatore = function (nome) {<br />
alert ("Ciao, " + nome + "!");<br />
};</pre><br />
Ci trovate qualcosa di strano?<br />
<br />
Magari l’avete già usato un sacco di volte, ma non ci avete mai fatto caso. Quel che stiamo facendo è assegnare una funzione a una variabile, operazione assolutamente lecita nel JS e che somiglia molto a ciò che facciamo nel C++ quando assegniamo un indirizzo di funzione a un puntatore.<br />
<br />
Questo tipo di funzioni si definiscono ''function expressions'' e sono davvero molto comuni.<br />
<br />
<br/>Come potete notare, la funzione che andiamo ad assegnare alla variabile ‘sembroUnPuntatore’ non ha nome. Anche questo è molto comune: si chiamano ''funzioni anonime'' e si possono invocare tramite la variabile cui sono assegnate. Nel C++ sono state introdotte in modo ufficiale solo nel 2011 e si chiamano ''funzioni lambda'', e in effetti stanno riscuotendo una grande successo.<br />
<br />
<br/>Attenzione! Questa non è solo una dichiarazione di funzione, ma anche un’espressione, perciò '''deve''' essere conclusa da un punto e virgola!<br />
<br />
<br/>Riassumendo: nel JS è possibile creare funzioni senza nome, dette funzioni anonime, che non presentano nessuna differenza con quelle ‘tradizionali’ se non questa: che non hanno nome.<br />
<br />
Le funzioni anonime possono essere assegnate alle variabili, le quali in tal caso sembrano assomigliare moltissimo a quelli che nel C++ si chiamano puntatori a funzione. Le funzioni assegnate alle variabili, dette ''function expressions'', possono essere invocate tramite tali variabili.<br />
<br />
Le ''function expressions'' devono essere concluse con un punto e virgola.<br />
<br />
<br/>Se dovessimo trattare le ''closure'' in modo esaustivo dovremmo introdurre un sottoinsieme delle funzioni anonime che si chiamano ''self-invoking function expressions'', ma per i nostri fini non è necessario.<br />
<br />
<br/>Procediamo un altro pezzo verso le ''closure''. Nel codice soprastante abbiamo definito una variabile e le abbiamo assegnato una funzione. Se quella variabile si trova fuori da ogni funzione, sarà una variabile globale. Ma il bello è che la possiamo definire all’interno di un’altra funzione:<br />
<pre>function esterna () {<br />
<br />
var saluto = document.getElementById("battesimo").value;<br />
<br />
var sembroUnPuntatore = function (nome) {<br />
alert ("Ciao, " + nome + "!");<br />
};<br />
<br />
}</pre><br />
Se incollassimo tale funzione nel nostro codice precedente e aggiungessimo alla funzione battezza() un rigo siffatto:<br />
<pre>esterna();</pre><br />
forse qualcuno si potrebbe aspettare che alla pressione del pulsante “battezza” compaia un messaggio di saluto. Non vi resta che provare.<br />
<br />
Successo niente? No? Beh, non c’è nulla di strano: infatti noi abbiamo definito una funzione, ma non l’abbiamo mai invocata. Per invocarla bisogna passare dalla variabile a cui è assegnata:<br />
<pre>sembroUnPuntatore(saluto);</pre><br />
Per cui ecco il codice completo della nuova funzione:<br />
<pre>function esterna () {<br />
var saluto = document.getElementById("battesimo").value;<br />
<br />
var sembroUnPuntatore = function (nome) {<br />
alert ("Ciao, " + nome + "!");<br />
};<br />
<br />
sembroUnPuntatore(saluto);<br />
}</pre><br />
Come vedete la sintassi di una funzione ‘tradizionale’ non anonima e quella di una function expression non varia gran ché (ma ricordatevi il punto e virgola!).<br />
<br />
<br/>A questo punto siamo in grado di rispondere alla domanda: cosa sarà mai una funzione genitore?<br />
<br />
Dall’esempio appena visto siamo venuti a conoscenza del fatto che nel JS le funzioni possono essere incluse una dentro l’altra, e in tal caso quella contenitrice è detta ‘parent’, ossia genitore, di quella contenuta.<br />
<br />
Nel nostro esempio ''esterna()'' è la funzione ''parent'' della ''function expression'' ‘sembroUnPuntatore’.<br />
<br />
<br/>Da quanto sopra dovrebbe essere già intuibile che, quando parliamo di una ''closure'', stiamo parlando di una funzione che è contenuta in un’altra funzione.<br />
<br />
La parte da spiegare è quella che dice “…può accedere allo spazio di visibilità del suo genitore…”.<br />
<br />
In realtà il concetto è molto semplice e un esempio lo chiarirà subito; guardate questa nuova versione della funzione ''esterna()'':<br />
<pre>function esterna () {<br />
var saluto = document.getElementById("battesimo").value;<br />
<br />
var sembroUnPuntatore = function (nome) {<br />
var testo = "Ciao, " + nome + "! Il robottino si chiama " + saluto + ".";<br />
alert (testo);<br />
};<br />
<br />
sembroUnPuntatore("Teodoro");<br />
}</pre><br />
Provate a scrivere un nome a vostro piacere nel campo di testo “battezza” (che non sia Teodoro, però!) e guardate un po’ cosa succede.<br />
<br />
<br/>[[File:JS 01.png|JS_01.png]]<br />
<br />
<br/>Sorpresa! La nostra funzione anonima ha avuto accesso alla variabile ‘saluto’ anche se si troverebbe, a una prima occhiata, fuori del suo spazio di visibilità.<br />
<br />
Abbiamo quindi imparato una nuova regola: le funzioni anonime possono ‘vedere’ le stesse variabili che vede la funzione ''parent'', ossia quelle locali alla funzione ''parent'', ivi compresi gli argomenti, e quelle globali.<br />
<br />
Attenzione! Questa regola non vale nel C++ dove alle funzioni lambda deve essere data una esplicita autorizzazione per accedere alle variabili della funzione che le contiene.<br />
<br />
<br/>Questo è il significato dell’espressione “può accedere allo spazio di visibilità del suo genitore”: la funzione anonima contenuta può accedere alle variabili nello spazio di visibilità della funzione contenitore.<br />
<br />
<br/>Ci può essere d’aiuto questa considerazione?<br />
<br />
Sì, se la uniamo all’ultima parte della definizione: “…perfino dopo che la funzione genitore è terminata”.<br />
<br />
<br/>Saltiamoci dentro a piè pari con un esempio.<br />
<br />
Abbiamo definito la variabile ‘sembroUnPuntatore’ come locale, ma basta levarci il ''var'' davanti e diventa globale. Facciamolo. Poi '''spostiamo''' (NON copiamo) la riga<br />
<pre>sembroUnPuntatore("Teodoro");</pre><br />
in battezza(), subito sotto<br />
<pre>esterna();</pre><br />
Fatto? Provate a fare il refresh con F5 e guardate un po’ cosa succede quando scegliete un nome e fate click su battezza.<br />
<br />
<br/>[[File:JS 02.png|JS_02.png]]<br />
<br />
<br/>Riuscite a cogliere le implicazioni?<br />
<br />
Con l’istruzione<br />
<pre>esterna();</pre><br />
in battezza() noi invochiamo la relativa funzione, ma, come abbiamo visto prima, senza chiedere esplicitamente di dare il via alla funzione anonima attribuita alla variabile ‘sembroUnPuntatore’, essa non viene eseguita.<br />
<br />
La successiva riga in ''battezza()'',<br />
<pre>sembroUnPuntatore("Teodoro");</pre><br />
invoca quella funzione anonima. La funzione anonima è in grado di accedere al valore della variabile ‘saluto’ che è locale a esterna().<br />
<br />
Fino a qui ci eravamo già arrivati. Ma ora ripensate un attimo a a ciò che è appena successo: la funzione anonima è stata eseguita, ma… '''perché mai avrebbe dovuto?'''<br />
<br />
La funzione ''parent'', ''esterna()'', è una comune funzione ‘tradizionale’. Una volta che è stata terminata e il flusso di istruzioni è tornato in ''battezza()''… beh, quello che abbiamo più volte detto è che il suo ‘ambiente’ viene distrutto: il computer libera la memoria, riutilizzandola per altri scopi, e trasformando tutti in nostri dati, compreso il valore di ‘saluto’, in nient'altro che spazzatura.<br />
<br />
<br/>Come mai allora la funzione anonima è in grado di leggere il contenuto della variabile ‘saluto’ il cui nome dovrebbe addirittura essere andato perduto?<br />
<br />
<br/>La risposta è molto semplice: quello che abbiamo detto è tutto vero, solo che lo abbiamo detto per il C++&nbsp;:-)<br />
<br />
Il JavaScript funziona in un’altra maniera e in questo caso la differenza è palpabile: nel JS, quando create una ''closure'', ciò che fate in buona sostanza è ‘congelare’ lo stato della funzione ''parent'', che a quel punto non viene più distrutta. Al termine della sua esecuzione rimane a occupare la memoria, tant’è che è possibile, tramite le funzioni anonime, accedere a tutte le sue variabili, che troveremo nello stato in cui le abbiamo lasciate.<br />
<br />
<br/>Ecco infine risolto il mistero della definizione delle ''closure'' che avevamo trovato, e che forse conviene rileggere per essere sicuri di aver capito:<br />
<br />
<br/>“una ''closure'' è una funzione che può accedere allo spazio di visibilità del suo genitore, perfino dopo che la funzione genitore è terminata”<br />
<br />
<br/>Credo sia abbastanza intuitivo il motivo del largo uso delle ''closure'' nel JS, visto che consentono di creare insiemi di dati che non muoiono mai (o meglio: non muoiono finché la variabile cui sono stati assegnati non muore).<br />
<br />
Spero sia abbastanza intuitivo anche ciò che andremo a fare ora: ossia utilizzare le funzioni anonime come metodi per accedere a proprietà private di una funzione: in questa maniera potremo finalmente costruire un oggetto simile a quelli che progetteremo nel C++.<br />
<br />
== Un robottino con le closure ==<br />
<br />
Cominciamo con il nocciolo della questione, ossia la funzione robottino:<br />
<pre>function Robottino (pa_nome) {<br />
var nome = pa_nome;<br />
var carica = 100;<br />
var x = 0;<br />
var y = 0;<br />
}</pre><br />
Come vedete siamo tornati a dichiarare tutte le variabili come locali. Quel che dobbiamo fare ora è riportare tutte le funzioni che abbiamo scritto in precedenza in questo alveo, facendole diventare funzioni anonime e assegnandole a delle variabili.<br />
<br />
C’è però da introdurre un’altra novità: per un problema ‘tecnico’ che ora non è il caso di affrontare perché ci porterebbe troppo lontano, i nomi di queste variabili conviene siano preceduti dalla parola ''this''.<br />
<br />
Mi rendo conto che non è molto carino da parte mia non spiegare il significato di ''this'' nel JS, ma ci sono due controindicazioni:<br />
<br />
#''this'' non è così semplice da usare come a prima vista potrebbe sembrare. Una spiegazione breve darebbe l’illusione di aver capito mentre ci sono diverse trappole in agguato. Penso sia più saggio lasciare che venga spiegata in modo dettagliato in altra occasione.<br />
#Anche il C++ ha la sua parola ''this'' e il fatto è che '''i significati delle due non coincidono''.''''' Pertanto, dato che nel C++ ''this'' è molto meno usata e ora ne possiamo rimandare la trattazione, preferisco scegliere di saltare a piè pari l’argomento.<br />
<br />
Tratteremo quindi ''this'' come l’espressione ''using namespace std'': qualcosa che ha la sua importanza, ma ora ci basta sapere che va messo senza conoscerne il perché.<br />
<br />
<br/>La prima funzione di cui ci siamo occupati è stata ''getNome()''. Era così:<br />
<pre>function getNome() {<br />
return nome;<br />
}</pre><br />
Ricominciamo da lei. Direi per semplicità che il nome della funzione può diventare il nome della variabile preceduto da this: tanto la funzione deve diventare anonima!<br />
<pre>this.getNome = function () {<br />
return nome;<br />
};</pre><br />
Non dimenticate il punto e virgola! Questa ora è una function expression. Ricordiamoci che questa funzione, essendo incorporata in un’altra, è in grado di accedere alle variabili della funzione parent anche se sono locali (come a esempio ‘nome’).<br />
<br />
Visto che stiamo lavorando all’interno di una funzione ''parent'' e il codice è molto breve, ci prendiamo una piccola licenza e lo scriviamo tutto su una riga:<br />
<pre>this.getNome = function () { return nome; };</pre><br />
Direi che abbiamo reso il codice più facile da leggere.<br />
<br />
<br/>Bon. Possiamo procedere con la funzione di cui ci eravamo occupati subito dopo, ''scriviPosizione()'':<br />
<pre>function scriviPosizione() {<br />
scriviPos = document.getElementById("pos");<br />
scriviPos.innerHTML = "x = " + x + ", y = " + y;<br />
}</pre><br />
Anche qui possiamo riciclare il nome della funzione per farlo diventare il nome della variabile; per il resto, il codice rimane identico:<br />
<pre>this.scriviPosizione = function () {<br />
scriviPos = document.getElementById("pos");<br />
scriviPos.innerHTML = "x = " + x + ", y = " + y; <br />
};</pre><br />
Proseguiamo a grandi passi con le funzioni successive<br />
<pre>function vaiSu() {<br />
y += 1;<br />
scriviPosizione();<br />
scriviCarica(5);<br />
}<br />
<br />
Anche questa rimane identica:<br />
<br />
this.vaiSu = function () {<br />
y += 1;<br />
this.scriviPosizione();<br />
this.scriviCarica(5);<br />
};</pre><br />
La stessa logica si può applicare alle altre tre che ‘muovono’ il robottino.<br />
<br />
Per finire, ricicliamo anche il codice di ''scriviCarica()'':<br />
<pre>function scriviCarica(variazione) {<br />
var scriviCar = document.getElementById("carica");<br />
carica -= variazione; <br />
scriviCar.value = carica;<br />
}</pre><br />
Che rimane:<br />
<pre>this.scriviCarica = function (variazione) {<br />
var scriviCarica = document.getElementById("carica");<br />
carica -= variazione; <br />
scriviCarica.value = carica;<br />
};</pre><br />
Adesso dobbiamo fronteggiare il cambiamento più vistoso, quello della funzione battezza(). La versione originaria recitava così:<br />
<pre>function battezza () {<br />
var battesimo = document.getElementById("battesimo").value; <br />
Robottino(battesimo);<br />
<br />
var htmlNome = document.getElementById("nome");<br />
htmlNome.innerHTML = getNome();<br />
scriviPosizione();<br />
scriviCarica(0);<br />
}</pre><br />
Le prime due righe possono anche rimanere inalterate, ma le modifiche che abbiamo portato alla funzione Robottino() l’hanno fatta diventare qualcosa di un po’ diverso, ossia una funzione di un tipo che di solito si definisce object constructor function, o anche solo constructor function.<br />
<br />
Questo tipo di funzioni servono a descrivere i dettagli di un oggetto, che sono in primo luogo le sue proprietà e i suoi metodi. Questa struttura, una volta descritta, non basta a creare da sola un oggetto, ma, come tutte le funzioni, per assolvere al suo compito deve essere invocata.<br />
<br />
Ci dobbiamo rendere conto però che non la invocheremo una volta sola: se abbiamo capito come funzionano le ''closure'', ci dovrebbe essere chiaro che una volta invocata, questa funzione non morirà più. Rimarrà in qualche modo congelata, a nostra disposizione, conservando con sé il valore di tutte le proprietà contenute.<br />
<br />
Tutte le volte che useremo uno dei suoi metodi, accederemo sempre allo stesso spazio di memoria, quello della stessa funzione, che non è mai stata distrutta.<br />
<br />
<br/>Adesso ragioniamoci un po’ su.<br />
<br />
Se quello che abbiamo detto fosse vero, allora vorrebbe dire che non potremmo mai avere più di un robottino per volta che si aggira per la nostra stanza!<br />
<br />
Cerchiamo di immaginarci la sequenza: noi invochiamo la funzione. Il computer la carica in memoria. Lì lei rimane fino alla fine del programma.<br />
<br />
Se la invocassimo una seconda volta, cosa succederebbe visto che non è mai ‘morta’? Avremmo un messaggio di errore? Si bloccherebbe il programma?<br />
<br />
<br/>Niente di tutto questo: l’interprete JS sarebbe in grado di soddisfare la nostra richiesta, ma pagando un prezzo. Infatti libererebbe un nuovo spazio di memoria dove caricare la nostra '''nuova''' ''constructor function'', ricreando tutte le proprietà, e dandoci accesso alla nuova funzione. Tutti i dati della vecchia sarebbero per noi resi inaccessibili.<br />
<br />
<br/>Conclusione: potremmo avere un solo robottino alla volta.<br />
<br />
<br/>Sarebbe un grosso limite, non vi sembra? Per fortuna il JS offre una soluzione al problema, e anche piuttosto semplice: possiamo assegnare la nostra ''constructor function'' a una variabile né più né meno come abbiamo fatto con le funzioni anonime.<br />
<br />
Questo ci consente di invocare la funzione quante volte vogliamo, assegnandola ogni volta a variabili diverse. Abbiamo già visto che alle funzioni assegnate alle variabili si può accedere tramite il nome di variabile; grazie a questo meccanismo, saremo in grado di invocare i suoi metodi.<br />
<br />
In questo modo potremo creare quanti robottini vogliamo, facendo sì che il computer li riconosca grazie al nome della variabile.<br />
<br />
<br/>La sintassi per ‘collegare’ una ''constructor function'' a una variabile è un po’ diversa da quella tradizionale e fa uso della parola chiave ''new'':<br />
<pre>var miaVariabile = new constructorFunction (argomenti);</pre><br />
Credo che la parola new sia molto d’aiuto in questo caso, anziché rappresentare una difficoltà, perché enfatizza il fatto che stiamo creando un nuovo esemplare del nostro oggetto, che si può aggiungere a quelli esistenti, se ce ne sono.<br />
<br />
Per ''new'' faremo però come per ''this'': la prenderemo per buona così com’è senza approfondirla e in buona misura per lo stesso motivo: anche nel C++ esiste ''new'', ma ha il suo significato, che non è identico a questo. Quindi ce ne occuperemo lì, ma non qui.<br />
<br />
Nel nostro caso, visto che vogliamo rendere la nostra variabile globale, non useremo l’istruzione ''var''.<br />
<br />
Supponendo di voler chiamare la variabile rbtnn e tenendo di conto che la ''constructor function'' è denominata ''Robottino()'', la dichiarazione verrà:<br />
<pre>rbtnn = new Robottino(battesimo);</pre><br />
Che è la novità più grande della nuova funzione battezza(). Il resto lo possiamo commentare dopo averlo scritto:<br />
<pre>function battezza () {<br />
var battesimo = document.getElementById("battesimo").value; <br />
var nome = document.getElementById("nome");<br />
<br />
// Senza 'var' diventa globale<br />
rbtnn = new Robottino(battesimo);<br />
<br />
nome.innerHTML = rbtnn.getNome();<br />
rbtnn.scriviPosizione();<br />
}</pre><br />
Possiamo finalmente prendere coscienza di ciò a cui serve l’istruzione punto ‘.’ nel JS: serve per accedere ai metodi di un oggetto. Si può dire che ‘rbtnn’ sia il nome del nostro oggetto – anche se, per l’appunto, contiene una variabile che si chiama ‘nome’ e questo può far fare confusione.<br />
<br />
Il fatto che contenga una proprietà denominata ‘nome’ è una pura coincidenza; avrebbe potuto non esserci.<br />
<br />
Per il compilatore, il nome dalla variabile cui è stata assegnata la ''constructor function'' è il nome dell’oggetto. Se volessimo al rigo successivo potremmo scrivere:<br />
<pre>robottino2 = new Robottino("Mario");</pre><br />
e creeremmo un nuovo oggetto denominato ‘robottino2’.<br />
<br />
Qualora scrivessimo:<br />
<pre>robottino2.scriviPosizione();</pre><br />
il computer non farebbe confusione: andrebbe a eseguire il metodo scriviPosizione() contenuto nello spazio di memoria assegnato a ‘robottino2’.<br />
<br />
<br/>La conclusione qual è?<br />
<br />
Nel JS ci sono diversi modi per creare un oggetto, ma quello che abbiamo scelto noi richiedere due passaggi:<br />
<br />
#prima si scrive una funzione, detta prototipo (''prototype'') dell’oggetto, ma nota anche come funzione costruttore (''constructor function''); questa funzione contiene tutti i metodi e le proprietà dell’oggetto.<br />
#In un secondo momento, si invoca la funzione quante volte si vuole, assegnandola ogni volta ad una variabile diversa; in questo modo creiamo quante copie vogliamo del nostro oggetto, a cui potremo accedere tramite le variabili utilizzate.<br />
<br />
Il primo passo consiste quindi nel creare una descrizione del nostro oggetto, una sorta di modello o stampo. In seguito useremo questo stampo per creare copie dell’oggetto.<br />
<br />
<br/>Concludiamo dando un’occhiata a quella che a una prima occhiata potrebbe sembrare una controindicazioni di questo metodo, e invece rappresenta il suo punto di forza.<br />
<br />
<br/>A questo punto non abbiamo più una via diretta per collegare a funzione ''vaiSu()'' richiesta dal codice HTML con il metodo ''vaiSu'' del nostro robottino.<br />
<br />
Infatti per arrivare a tale metodo dobbiamo conoscere il nome della variabile cui è stata assegnata la ''constructor function'' ''Robottino()''. In altre parole, una volta ci potremmo trovare a invocare:<br />
<pre>rbtnn.vaiSu();</pre><br />
e una volta:<br />
<pre>robottino2.vaiSu();</pre><br />
Perciò, cosa scriveremo nel nostro file HTML?<br />
<br />
Beh, lo HTML non nasce per avere la flessibilità del JS, pertanto non possiamo sperare che ci offra soluzioni altrettanto semplici; quindi è nel JS che dobbiamo cercare.<br />
<br />
<br/>A dire il vero la domanda nel nostro programma è molto scolastica perché all’atto pratico tutto il codice è pensato per interagire con un solo robottino. Si tratta quindi di un puro esercizio ‘di stile’ e ci serve solo per dare un’occhiata a un tipo di codice che si usa tantissimo, ma le prime volte può sembrare un’inutile perdita di tempo.<br />
<br />
<br/>La soluzione al nostro problema consiste nel nascondere la chiamata alla funzione ‘vera’ all’interno di una funzione di comodo:<br />
<pre>function vaiSu () {<br />
rbtnn.vaiSu();<br />
}</pre><br />
Chi pensa che sarebbe meglio evitare questo passaggio e cercare un modo per chiamare direttamente il metodo partendo dallo HTML commette un errore concettuale.<br />
<br />
Molti si potrebbero domandare se gli oggetti servono davvero a qualcosa e tutto questo tempo perso a cercare di rendere private delle proprietà abbia un senso. Abbiamo già dato una prima risposta all’inizio del tutorial e potremmo aggiungere che quello di programmare a oggetti oggi è in ‘must’: tutti i linguaggi stanno cercando di spostarsi verso la programmazione a oggetti.<br />
<br />
<br/>Se quindi vogliamo usare gli oggetti, non possiamo considerare una perdita di tempo il fatto che ci costringano a una certa sintassi, spesso più prolissa di quella della programmazione ‘tradizionale’.<br />
<br />
<br/>Il codice completo del file privati.js è ora questo:<br />
<br />
<pre>function Robottino (pa_nome) {<br />
var nome = pa_nome;<br />
var carica = 100;<br />
var x = 0;<br />
var y = 0;<br />
<br />
this.getNome = function () { return nome; };<br />
<br />
this.scriviPosizione = function () {<br />
var scriviPos = document.getElementById("pos");<br />
scriviPos.innerHTML = "x = " + x + ", y = " + y; <br />
};<br />
<br />
this.scriviCarica = function (variazione) {<br />
var scriviCarica = document.getElementById("carica");<br />
carica -= variazione; <br />
scriviCarica.value = carica;<br />
};<br />
<br />
this.vaiSu = function () { y += 1; this.scriviPosizione(); this.scriviCarica(5); };<br />
this.vaiGiu = function () { y -= 1; this.scriviPosizione(); this.scriviCarica(5); };<br />
this.vaiDx = function () { x += 1; this.scriviPosizione(); this.scriviCarica(5); };<br />
this.vaiSx = function () { x -= 1; this.scriviPosizione(); this.scriviCarica(5); };<br />
}<br />
<br />
function battezza () {<br />
var battesimo = document.getElementById("battesimo").value; <br />
var nome = document.getElementById("nome");<br />
<br />
// Senza 'var' diventa globale<br />
rbtnn = new Robottino(battesimo);<br />
<br />
nome.innerHTML = rbtnn.getNome();<br />
rbtnn.scriviPosizione();<br />
}<br />
<br />
function vaiSu () {<br />
rbtnn.vaiSu();<br />
}<br />
<br />
function vaiGiu () {<br />
rbtnn.vaiGiu();<br />
}<br />
<br />
function vaiDx () {<br />
rbtnn.vaiDx();<br />
}<br />
<br />
function vaiSx () {<br />
rbtnn.vaiSx();<br />
}</pre><br />
<br />
== Conclusioni, miglioramenti ed esercizi ==<br />
<br />
Ci sarebbero mille altre cose da dire, ma come sempre abbiamo usato il JS come apripista, perciò ci siamo limitati a sottolineare gli aspetti che ci facevano comodo per arrivare al C++.<br />
<br />
Questi aspetti sono:<br />
<br />
*un oggetto è in buona sostanza un blocco di codice che include proprietà e metodi; nel JS questo blocco di codice è una funzione, mentre nel C++ non è così;<br />
*questo blocco di codice ha un nome, ma è solo il nome dello ‘stampo’: gli oggetti che poi saranno creati avranno ognuno il proprio nome;<br />
*una funzione anonima può essere contenuta dentro un’altra funzione;<br />
*un oggetto non deve per forza avere dei membri privati, ma la possibilità di rendere qualcosa inaccessibile dall’esterno è uno dei suoi principali vantaggi.<br />
<br />
Prima di lasciare il JS, invito a fare un po’ di esperimenti in proprio per entrare più dentro i concetti trovati. Si potrebbe ad esempio provare a aggiungere una funzione che consenta di cambiare il nome al robottino.<br />
<br />
Si immagini ad esempio di aggiungere il seguente blocco di codice al file HTML, subito sotto l’istruzione ''&lt;/table&gt;'':<br />
<pre> <div class="stacco_2em"><br />
<label>Rinomina il robottino: </label><br />
<input id="rinomina" type="text" /><br />
<input type="button" value="rinomina" onclick="rinomina();" /><br />
</div></pre><br />
Che codice si potrebbe scrivere per gestire questa aggiunta?<br />
<br />
<br/>Di seguito offro una possibile soluzione, però immersa in una nuova versione di “privati.js”. L’obiettivo è mostrare come si possono affrontare i problemi da punti di vista diversi, ottenendo risultati simili e spesso soddisfacenti.<br />
<br />
Il codice che segue presenta delle ‘sviste’ (per esempio, una variabile locale è dichiarata due volte…) e delle forzature. Cercare di individuare gli errori e di capire vantaggi e svantaggi delle diverse versioni del codice può essere un esercizio come un altro.<br />
<pre>function Robottino (pa_nome, HTMLpos) {<br />
var nome = pa_nome;<br />
var carica = 100;<br />
var x = 0;<br />
var y = 0;<br />
var scriviPos;<br />
var scriviCarica;<br />
<br />
this.getNome = function () { return nome; };<br />
this.setNome = function (pa_nome2) { nome = pa_nome2; };<br />
<br />
this.getPosizioneX = function () { return x; };<br />
this.getPosizioneY = function () { return y; };<br />
<br />
this.scriviPosizione = function () {<br />
scriviPos = HTMLpos&nbsp;? HTMLpos&nbsp;: document.getElementById("pos");<br />
scriviPos.innerHTML = "x = " + x + ", y = " + y; <br />
};<br />
<br />
this.scriviCarica = function (variazione) {<br />
var scriviCarica = document.getElementById("carica");<br />
carica -= variazione; <br />
scriviCarica.value = carica;<br />
};<br />
<br />
this.vaiSu = function (passi) { y += passi; this.scriviPosizione(); this.scriviCarica(5); };<br />
this.vaiGiu = function (passi) { y -= passi; this.scriviPosizione(); this.scriviCarica(5); };<br />
this.vaiDx = function (passi) { x += passi; this.scriviPosizione(); this.scriviCarica(5); };<br />
this.vaiSx = function (passi) { x -= passi; this.scriviPosizione(); this.scriviCarica(5); };<br />
}<br />
<br />
function battezza () {<br />
var battesimo = document.getElementById("battesimo").value; <br />
var nome = document.getElementById("nome");<br />
var pos = document.getElementById("pos");<br />
<br />
// Senza 'var' diventa globale<br />
rbtnn = new Robottino(battesimo, pos);<br />
<br />
nome.innerHTML = rbtnn.getNome();<br />
rbtnn.scriviPosizione();<br />
}<br />
<br />
function rinomina () {<br />
var nuovoNome = document.getElementById("rinomina").value;<br />
var nome = document.getElementById("nome");<br />
<br />
rbtnn.setNome(nuovoNome);<br />
nome.innerHTML = rbtnn.getNome();<br />
}<br />
<br />
function vaiSu () {<br />
rbtnn.vaiSu(1);<br />
}<br />
<br />
function vaiGiu () {<br />
rbtnn.vaiGiu(1);<br />
}<br />
<br />
function vaiDx () {<br />
rbtnn.vaiDx(1);<br />
}<br />
<br />
function vaiSx () {<br />
rbtnn.vaiSx(1);<br />
}</pre><br />
Nel codice ci sono anche due novità, la riga:<br />
<pre>scriviPos = HTMLpos&nbsp;? HTMLpos&nbsp;: document.getElementById("pos");</pre><br />
e la riga:<br />
<pre>rbtnn = new Robottino(battesimo, pos);</pre><br />
Diamoci un’occhiata insieme, partendo dalla seconda.<br />
<br />
In questa nuova versione di “privati.js” immaginiamo che si provi ad usare due robottini insieme. Miracolosamente, essi possono ‘nascere’ nello stesso punto (il centro della stanza), ma poi la posizione di uno dei due dovrà essere scritta su un ‘display’ diverso (ossia, un altro campo di testo). Questo nuovo campo di testo potrebbe essere passato al robottino tramite il parametro ‘pos’ al momento della creazione.<br />
<br />
Gestire questa novità non sarà facile, ma lo lasciamo come esercizio.<br />
<br />
<br/>L’altra riga è strettamente connessa a questa: nel caso ci sia un secondo (o un terzo, un quarto…) robottino, la variabile ‘scriviPos’ non dovrà puntare al campo di testo con id = "pos", ma a quello passato tramite l’argomento ‘HTMLpos’.<br />
<br />
Come fa il JS a sapere quale campo di testo usare?<br />
<br />
L’istruzione sembra difficile, ma leggendola con calma la si può decifrare con una certa facilità.<br />
<br />
<br/>La sintassi è la seguente:<br />
<pre>condizione_vera_o_falsa &nbsp;? conseguenza_se_vero&nbsp;: conseguenza_se_falso</pre><br />
Si tratta di una cosa simile a un’istruzione if, ma sta tutto su una riga.<br />
<br />
All’inizio della riga si mette la condizione, anche senza parentesi. Nel nostro caso basta scrivere “HTMLpos”, che sta a significare:<br />
<pre>nel caso che la variabile HTMLpos sia vera (nel senso di sia stata definita, abbia un valore)…</pre><br />
Dopo la condizione si mette il punto interrogativo ‘?’, che serve a distinguere la condizione delle sue conseguenze.<br />
<br />
Dopo il punto interrogativo, si scrive la prima conseguenza, quella che deve accadere se la condizione è vera. Nel nostro caso, basta riscrivere “HTMLpos”, che in questo caso vuol dire:<br />
<pre>(nel caso in cui la variabile HTMLpos abbia un valore) usa, per scriviPos, il valore di HTMLpos</pre><br />
Dopo la prima conseguenza si mette il simbolo di due punti ‘:’. Questo simbolo termina la prima conseguenza e introduce la seconda, quella che si deve realizzare se la condizione è falsa.<br />
<br />
Dopo i due punti si trova la conseguenza di una condizione falsa, nel nostro caso “document.getElementById("pos")”. Il suo significato è:<br />
<pre>(nel caso in cui la variabile HTMLpos non abbia alcun valore) <br />
usa, per scriviPos, il valore restituito dalla funzione document.getElementById("pos")</pre><br />
Da ultimo c’è il buon vecchio punto e virgola.<br />
<br />
<br/>Un ultimo esercizio che suggerisco (di cui però non sto a proporre alcuna soluzione) consiste nel fare in modo che, esaurita la carica, il robottino si fermi.<br />
<br />
<br/>Ora però è il momento di lasciare il JavaScript.<br />
<br />
= Un robottino in C++ =<br />
<br />
Proviamo a costruire il nostro primo ''oggetto'' in C++. Cercheremo di ottenere qualcosa di simile a quello che siamo riusciti a mettere insieme con il JavaScript.<br />
<br />
<br />
<br />
== Cominciamo con classe ==<br />
<br />
Iniziamo con il creare un nuovo progetto, che chiameremo Robottino e salveremo sempre nella solita cartella. Il progetto sarà sempre un '''Non-Qt Project''' → '''Plain C++ Project'''.<br />
<br />
<br/>[[File:Qt IV 01.png|Qt_IV_01.png]]<br />
<br />
<br/>Qt Creator ci presenta la classica schermata “Hello Word!”, che noi cercheremo di sfruttare a nostro comodo.<br />
<br />
<br/>Dovete sapere che un sacco di IDE… Vi ricordate cos’è un IDE, vero? Un ambiente integrato di sviluppo, come ad esempio Qt… Beh, un sacco di IDE offrono una funzione apposita per creare ''oggetti'' e Qt non fa eccezione. Infatti, se tornate a sbirciare sotto '''File''' → '''New File or Project''', nella finestra che si apre e ormai dovreste trovare familiare, nella colonna di sinistra, trovate la scritta '''File and Classes'''.<br />
<br />
<br/>Gli ''oggetti'' nel C++ si creano tramite le ''class'' (nel JavaScript abbiamo visto la funzione prototipo, che è la cosa più simile) e alcune delle opzioni che appaiono lì sotto servono proprio per generare lo scheletro di una ''class'' tramite una procedura automatizzata, un po’ come Creator fa quando, nel creare un nuovo progetto, ci aggiunge in automatico un file ''main.cpp'' e dentro quel file il codice di “Hello Word!”.<br />
<br />
Se facciamo click su “C++”, vedremo che le opzioni nella colonna centrale cambiano, offrendoci la possibilità di creare una ''class''.<br />
<br />
<br/>[[File:Qt IV 08.png|Qt_IV_08.png]]<br />
<br />
<br/>Il motivo che spinge i progettisti di IDE a offrire questo genere di servizi è che di solito le ''class'' si scrivono su file separati.<br />
<br />
Vi ricordate quando abbiamo preso un file HTML dove c’era dentro di tutto e l’abbiamo suddiviso in tre parti, una per lo HTML, una per il JavaScript e una per i CSS? Beh, in teoria sarebbe giunto il momento di fare lo stesso con il C++: una ''class'' non dovrebbe stare insieme a ''main()'', il codice risulterebbe molto disordinato. Per ogni nuovo ''oggetto'' che vogliamo progettare dobbiamo scrivere una ''class'' e quella ''class'' dovrebbe stare in ben due file, nessuno dei quali dovrebbe essere quello in cui c’è ''main()''.<br />
<br />
Visto quindi che c’è tutto questo lavoro preparatorio da fare per confezionare una ''class'', ossia creare due nuovi file, dar loro dei nomi appropriati, e dopo scrivere il codice della ''class'' dividendolo nei due file secondo un certo criterio, ecco che gli IDE ci vengono in soccorso togliendoci una parte del lavoro più noioso.<br />
<br />
<br/>Però ora noi compiremo un crimine che farà storcere la bocca a più di una persona: scriveremo il codice della nostra ''class'' nel file ''main.cpp'', subito sotto ''main()''. La cosa importante in questo momento è capire ''che cosa'' stiamo facendo, e soltanto dopo ci porremo la domanda se esisteva un modo un po’ più ‘ordinato’ di farlo.<br />
<br />
Visto che ci siamo messi d’accordo così, possiamo far click su ''Cancel'', o ''Annulla'' che sia, e tornare al nostro codice: infatti non useremo la procedura automatica ma scriveremo tutto da soli rigo per rigo.<br />
<br />
<br/>Andiamo subito a confermare un concetto: gli ''oggetti'' del C++ si creano tramite le ''class'', che non sono altro che blocchi di codice con un’etichetta, su per giù come le funzioni.<br />
<br />
Torniamo a ciò che abbiamo detto in conclusione al codice JS:<br />
<br />
*un oggetto è in buona sostanza un blocco di codice che include proprietà e metodi; nel JS questo blocco di codice è una funzione, mentre nel C++ non è così;<br />
<br />
Bene: nel C++ questo blocco di codice si chiama ''class''.<br />
<br />
<br/>La ''class'' è quindi l’equivalente della funzione prototipo o ''constructor function'' del JS.<br />
<br />
La differenza tra una ''class'' e un oggetto è molto concettuale: si dice che un oggetto è una ''istanza'' di una ''class''.<br />
<br />
Cosa vuol dire? Che la ''class'' è un po’ come uno stampo: una volta che lo abbiamo modellato, possiamo usarlo per creare tanti oggetti uguali fra di loro. A ognuno di questi oggetti potremo dare nomi diversi, ma saranno tutti identici uno all’altro perché tutti nati tramite la ''class'' che abbiamo scritto.<br />
<br />
Fino a qui, non troviamo molte differenze con ciò che abbiamo visto nel JS.<br />
<br />
Per ora basta ricordarsi che una ''class'' è uno stampo per creare oggetti: gli oggetti nati da una stessa ''class'' sono tutti uguali fra di loro.<br />
<br />
Se si tiene in mente questo, non dovremmo avere difficoltà a capire perché, per mantenere la promessa di parlare degli oggetti, ci mettiamo a studiare le ''class''.<br />
<br />
<br/>La parola inglese ''class'' viene di solito tradotta con classe. Ancora una volta pare che gli informatici dimostrino una scarsa attitudine all’uso del vocabolario giacché una scelta più accorta sarebbe stata ‘tipo’. Una ''class'' infatti, lo abbiamo appena detto, serve per generare oggetti di un certo ''tipo''. Gli oggetti di quel tipo saranno tutti uguali fra di loro.<br />
<br />
Viene quasi da sospettare che la parola classe sia stata scelta per la sua assonanza con quella inglese (''class'') invece che per il concetto che deve veicolare. Tuttavia anche in italiano la parola classe può significare gruppo o categoria, a esempio quando si parla di classe sociale intendendo con questa espressione persone di un certo ‘tipo’, magari contraddistinto da un dato livello di agiatezza. Di conseguenza anche noi ci adegueremo alla consuetudine e parleremo di classi per trattare le ''classes'', consolandoci magari con la considerazione che anche nei CSS è stata usata la stessa approssimazione.<br />
<br />
<br/>Andiamo quindi a vedere come si può creare lo stampo di un oggetto.<br />
<br />
Cerchiamo di ottenere l’equivalente della ''constructor function Robottino()'' del JS. Tanto per enfatizzare la similitudine, possiamo chiamare la nostra ''class'' con il nome Robot, che è simile, ma non identico, in modo che si riesca sempre a tenere ben distinti nella mente i due codici. Però le ''class'' del C++ '''non''' sono funzioni, per cui non faremo seguire la parentesi tonda ‘()’ al nome:<br />
<pre>class Robot {</pre><br />
Beh, l’inizio non è stato difficile&nbsp;:)<br />
<br />
Quindi, una ''class'' è un blocco di codice… sappiamo già che questo nel C++ implica una bella coppia di parentesi graffe ‘{}’. In più ha un nome, e anche in questo caso basta scriverlo all’inizio del blocco e il compilatore capisce che è il nome della classe. Non ci vuole molto per arrivare a concludere che tutte le nostre proprietà e i nostri metodi dovranno stare fra le parentesi graffe.<br />
<br />
A dire il vero, più avanti scopriremo che è più comodo scriverle da un’altra parte, ma da un punto di vista concettuale l’affermazione è giusta.<br />
<br />
<br/>Le due novità sono la parola chiave ''class'' e la mancanza di parentesi tonde, ma si tratta di due novità annunciate che ribadiscono una distinzione che voglio comunque ripetere: una ''class'' non ha nulla a che vedere con le funzioni.<br />
<br />
C’è però una similitudine con le ''function expressions'' del JS: anche la dichiarazione di una classe finisce con un punto e virgola.<br />
<br />
<br/>Quindi, andando avanti, possiamo dire che dovremo ottenere un codice del tipo:<br />
<pre>class Robot{<br />
// Qui metteremo proprietà e metodi<br />
};</pre><br />
L’ho scritto tutto bello appiccicato, come adorano i programmatori in C++.<br />
<br />
Proviamo a metterci dentro una proprietà e cerchiamo di scoprire cosa succede. Una proprietà di solito è una variabile, perciò questo codice dovrebbe andare bene:<br />
<pre>class Robot{<br />
int mia_proprieta;<br />
};</pre><br />
A questo punto abbiamo creato lo ‘stampo’ del nostro primo oggetto nel C++.<br />
<br />
Non sarà il più utile degli oggetti concepibili, ma dovrebbe funzionare. A questo punto, però, siamo nella situazione in cui ci siamo trovati nel JS quando abbiamo scritto la nostra ''constructor function Robottino()'': finché non l’abbiamo attribuita a una variabile tramite la parola ''new'', avevamo solo lo stampo, ma ancora nessun oggetto.<br />
<br />
<br/>Vi sorprenderà scoprire che in questo caso il C++ è più semplice e lineare del JS: infatti non è indispensabile usare la parola ''new''. Vi ricordate quando abbiamo detto che i ''vector'' e le ''string'' sono oggetti? Eppure come abbiamo fatto a dichiarare una variabile di tipo ''string''?<br />
<pre>string testo;</pre><br />
‘testo’ diventa una variabile di tipo string. Infatti, come abbiamo detto poco sopra, la parola class non andrebbe tradotta in modo forzato ‘classe’, ma in modo accurato ‘tipo’. Una class crea un nuovo tipo che si va ad aggiungere a quelli esistenti, come gli int e i long.<br />
<br />
Pertanto ecco come creare un esemplare (si dice una ''istanza'') del nostro oggetto Robot:<br />
<pre>Robot rbt;</pre><br />
Fine. Non serve altro.<br />
<br />
Per accedere alla nostra variabile ‘mia_proprieta’ basterà scrivere:<br />
<pre>rbt.mia_proprieta;</pre><br />
O forse no…?&nbsp;:-/<br />
<br />
Smettiamola di parlare in teoria e andiamo a guardarci un po’ di codice. Cominciamo con lo scheletro minimo possibile: la funzione ''main()'' –che nel C++ '''non''' può mancare!– e una classe vuota:<br />
<br />
<br/>[[File:Qt IV 02.png|Qt_IV_02.png]]<br />
<br />
<br/>E, per i pigroni:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
return 0;<br />
}<br />
<br />
class Robot{<br />
<br />
};</pre><br />
Questo codice compila senza problemi, ma ha un piccolo difetto: non fa assolutamente nulla. Non è un difetto da poco, ripensandoci.<br />
<br />
Forse è meglio metterci qualcosa dentro. In ''main()'' potremmo aggiungere:<br />
<pre>Robot rbt;</pre><br />
per creare un’istanza del nostro oggetto.<br />
<br />
Invece nell’oggetto potremmo inserire una proprietà, ma lasciamo stare quegli antipatici di numeri: mettiamoci una ''string'':<br />
<pre>string nome;</pre><br />
Venendo dal JS potremmo pensare che questa proprietà sia accessibile dall’esterno. Infatti non abbiamo fatto nulla per nasconderla, e nemmeno ci siamo preoccupati di scrivere complicate closure per accedervi… Beh, se la pensiamo così, il C++ è pronto a servirci amare delusioni.<br />
<br />
Inseriamo in ''main()'' la manipolazione minima possibile:<br />
<pre>rbt.nome = "Mario";<br />
cout << "rbt.nome = " << rbt.nome << endl << endl;</pre><br />
Proviamo a compilare il programma completo:<br />
<pre>#include <iostream><br />
<br />
<br />
using namespace std;<br />
<br />
<br />
int main()<br />
{<br />
Robot rbt;<br />
rbt.nome = "Mario";<br />
<br />
cout << "rbt.nome = " << rbt.nome << endl << endl;<br />
return 0;<br />
}<br />
<br />
class Robot{<br />
string nome;<br />
};</pre><br />
e ci troviamo davanti la faccia accigliata del nostro compilatore:<br />
<br />
<br/>[[File:Qt IV 03.png|Qt_IV_03.png]]<br />
<br />
<br/>&lt;/pre&gt;<br />
<br />
Simpatici quei messaggi di errore, vero? Andiamo a darci un’occhiata.<br />
<br />
Il primo recita: «In function main(): ‘Robot’ was not declared in this scope».<br />
<br />
Intanto traduciamolo, ma con una certa libertà: «Errori contenuti nella funzione main(): la parola 'Robot' non è accessibile all’interno di main()».<br />
<br />
<br/>Il significato dovrebbe essere chiaro, anche se il motivo forse è misterioso: ''main()'' non riesce a vedere il codice ''class Robot{…};''<br />
<br />
Gli altri errori sono una diretta conseguenza di questo: non potendo sapere cosa significa 'Robot', ''main()'' non capisce nemmeno cosa sia ‘rbt’, che noi vorremmo fosse un’istanza di ‘Robot’.<br />
<br />
<br/>Qui bisogna tenere presente la differenza fondamentale fra i linguaggi come il JS e i linguaggi come il C++: il JS è interpretato. Ciò significa che il codice viene caricato in memoria, ‘elaborato’ e poi eseguito. Il C++ invece è compilato: questo significa che il compilatore legge il file rigo per rigo per trasformarlo in linguaggio macchina. Nel punto in cui ha incontrato la nostra istruzione “Robot rbt”, ancora non aveva letto la definizione di Robot, pertanto non era in grado di sapere cosa volevamo.<br />
<br />
La cosa più semplice, quindi, è spostare la definizione della classe '''prima''' di ''main()'':<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
class Robot{<br />
string nome;<br />
};<br />
<br />
int main()<br />
{<br />
Robot rbt;<br />
rbt.nome = "Mario";<br />
<br />
cout << "rbt.nome = " << rbt.nome << endl << endl;<br />
return 0;<br />
}</pre><br />
Non ci resta che andare a vedere che disastro abbiamo combinato ora&nbsp;:-)<br />
<br />
<br />
<br />
== Violazione della privacy ==<br />
<br />
[[File:Qt IV 04.png|Qt_IV_04.png]]<br />
<br />
<br/>Sempre peggio!&nbsp;:-)<br />
<br />
Quattro messaggi di errore invece che tre.<br />
<br />
Ok, ci possiamo rilassare: in realtà il compilatore ci sta segnalando due volte la stessa cosa: abbiamo usato due volte la proprietà ‘nome’ di Robot, una volta al rigo 12 e una volta al rigo 14, che sono rispettivamente:<br />
<pre>12: rbt.nome = "Mario";<br />
14: cout << "rbt.nome = " << rbt.nome << endl << endl;</pre><br />
Se non abbiamo voglia di contare, ci possiamo fidare di Qt, che gentilmente ci evidenzia anche con dei pallini rossi le righe dove secondo lui abbiamo sbagliato qualcosa:<br />
<br />
<br/>[[File:Qt IV 05.png|Qt_IV_05.png]]<br />
<br />
<br/>Il fatto è, ci sta dicendo il compilatore, che «nome is private within this context». Anche se può essere un po’ intricato decifrare la frase intera, possiamo però cogliere l’essenza: ‘nome’ è ‘private’, pertanto non può essere liberamente utilizzata in ''main()''.<br />
<br />
<br/>Sorpresi? Non tanto forse. Il C++ nasce per essere un linguaggio a oggetti, il ché significa per garantire che si possa lavorare in tanti allo stesso codice senza interferire l’uno con l’altro. Pertanto ''parte dal presupposto'' che si voglia dichiarare le proprietà private; se non è ciò che desideriamo, dobbiamo specificarlo in modo esplicito, ma anche in questo caso non c’è nessuna difficoltà: basta scrivere ‘public:’:<br />
<pre>class Robot{<br />
public:<br />
string nome;<br />
};</pre><br />
Provare per credere. Il codice compila senza errori e dà il risultato atteso:<br />
<br />
<br/>[[File:Qt IV 06.png|Qt_IV_06.png]]<br />
<br />
<br/>Tutto si può dire fuorché il C++ non abbia un valido supporto per la programmazione a oggetti!<br />
<br />
<br/>La parola ‘public’ funziona con la logica “da qui in avanti”, nel senso che crea un punto di inizio: da quel momento in poi tutte le variabili dichiarate all’interno della ''class'' saranno accessibili dall’esterno. Questo significa che quelle dichiarate '''prima''' non lo saranno.<br />
<br />
Ad esempio:<br />
<pre>class unaClasse{<br />
int intero_privato;<br />
long intero_lungo_privato;<br />
string testo_privato;<br />
<br />
public:<br />
int intero_pubblico;<br />
long intero_lungo_pubblico;<br />
string testo_pubblico;<br />
};</pre><br />
In questo modo possiamo organizzare il codice secondo le nostre necessità. Anzi, dirò di più: se, dopo aver dichiarato un blocco della nostra classe ‘public’ dovessimo cambiare idea e volere altre variabili inaccessibili dall’esterno, beh, anche in questo caso nessun problema: esiste il corrispondente ‘private’:<br />
<pre>class unaClasse{<br />
int intero_privato;<br />
long intero_lungo_privato;<br />
string testo_privato;<br />
<br />
public:<br />
int intero_pubblico;<br />
long intero_lungo_pubblico;<br />
string testo_pubblico;<br />
<br />
private:<br />
int un_altro_intero_privato;<br />
long un_altro_intero_lungo_privato;<br />
string un_altro_testo_privato;<br />
};</pre><br />
(Per favore, non utilizzate mai dei nomi di variabile così lunghi nei vostri programmi!)<br />
<br />
Insomma, nel C++ possiamo fare decisamente come vogliamo e con gran facilità. Non voglio stare qui ora a parlare dell’istruzione ‘protected’, che crea delle variabili private, ma accessibili ad alcune funzioni, però posso introdurvi a un’altra curiosità.<br />
<br />
<br/>Abbiamo detto che per creare gli oggetti usiamo la parola chiave ''class'' che si aspetta che i membri debbano essere privati a meno che li dichiariamo ‘public’; non ci crederete, ma il C++ è così completo che offre anche anche l’alternativa opposta: con ''struct'' potete definire degli oggetti del tutto identici a quelli che potete ottenere con ''class'', eccetto che ''struct'' si aspetta che i membri siano pubblici, a meno che non li dichiariate ‘private’.<br />
<br />
In altre parole:<br />
<pre>struct unaStruct{<br />
int intero_pubblico;<br />
long intero_lungo_pubblico;<br />
string testo_pubblico;<br />
<br />
private:<br />
int intero_privato;<br />
long intero_lungo_privato;<br />
string testo_privato;<br />
<br />
public:<br />
int un_altro_intero_pubblico;<br />
long un_altro_intero_lungo_pubblico;<br />
string un_altro_testo_pubblico;<br />
};</pre><br />
Se non vi basta, vuol dire che siete proprio incontentabili!&nbsp;:-)<br />
<br />
Noi comunque ''struct'' la useremo pochissimo o per nulla, perché la sintassi ‘tradizionale’ per creare oggetti passa da ''class''. ''struct'' è un’eredità del C.<br />
<br />
<br/>Andiamo un altro po’ avanti.<br />
<br />
Perché usare proprietà pubbliche? Rendiamo ‘nome’ privata e poi facciamo in modo che per modificarla si debbano usare funzioni interne a Robot. Questa sarebbe la logica sottostante agli oggetti: fornire delle variabili che durino a lungo, ma non siano ‘facilmente’ modificabili, ossia non siano accessibili da chiunque senza limiti.<br />
<br />
Per modificare il contenuto della variabile ‘nome’ ci serve una funzione che accetti un parametro di tipo testo e lo inserisca in ‘nome’. Una cosa del tipo:<br />
<pre>void setNome(string battezza)<br />
{<br />
nome = battezza;<br />
}</pre><br />
Questa, come vedete, è una vera e propria funzione, con le sue parentesi tonde e senza punto e virgola alla fine. Mando a capo la parentesi graffa di apertura ‘{‘ perché è lo stile adottato da Stroustrup per le funzioni; un’abitudine, diciamo, ma voi potete fare come vi pare. Ricordiamoci che le funzioni che non restituiscono valori nel C++ devono essere dichiarate void.<br />
<br />
All’opposto, se vogliamo conoscere il valore della variabile ‘nome’, abbiamo bisogno di una funzione che restituisca una stringa:<br />
<pre>string getNome() <br />
{<br />
return nome;<br />
}</pre><br />
Per quelli che si fossero già dimenticati tutto dei tutorial precedenti, ricordo che return restituisce una copia del valore della variabile, quindi una copia dei dati contenuti nell’oggetto string. Quindi non stiamo violando la ‘intangibilità’ della variabile ‘nome’, la quale rimane inaccessibile dall’esterno, ma stiamo facendo una copia di ciò che vi è contenuto e stiamo spedendo tale copia.<br />
<br />
<br/>Giacché abbiamo deciso che ‘nome’ dovrà essere privata, le due funzioni potranno avervi accesso solo se sono contenute nella stessa ''class'':<br />
<pre>class Robot{<br />
string nome;<br />
<br />
void setNome(string battezza)<br />
{<br />
nome = battezza;<br />
}<br />
<br />
string getNome()<br />
{<br />
return nome;<br />
}<br />
<br />
};</pre><br />
Beh, in questo caso, se vogliamo aumentare la leggibilità, possiamo prenderci una licenza e mettere tutto sulla stessa riga:<br />
<pre>class Robot{<br />
string nome;<br />
<br />
void setNome(string battezza) { nome = battezza; }<br />
<br />
string getNome() { return nome; }<br />
};</pre><br />
Anche main() però dovrà essere diversa, perché non potrà più accedere a ‘nome’. Ecco qui una possibile versione:<br />
<pre>int main()<br />
{<br />
Robot rbt;<br />
rbt.setNome("Mario");<br />
<br />
cout << "rbt.nome = " << rbt.getNome() << endl << endl;<br />
return 0;<br />
}</pre><br />
Spero di non sembrare presuntuoso a dire che non mi sembra ci sia nulla da spiegare: l’istruzione<br />
<pre>rbt.setNome("Mario");</pre><br />
invia il parametro “Mario” all’argomento ‘battezza’ di setNome(), che lo inserisce in ‘nome’.<br />
<br />
L’istruzione<br />
<pre>rbt.getNome()</pre><br />
recupera il valore di ‘nome’ e lo invia a cout. Il resto dovrebbe essere chiaro.<br />
<br />
Proviamo a compilarlo e…<br />
<br />
<br/>[[File:Qt IV 07.png|Qt_IV_07.png]]<br />
<br />
<br/>PATATRAK!<br />
<br />
Un’altra bella distesa di messaggi d’errore&nbsp;:-)<br />
<br />
<br/>Okay, il C++ è davvero pignolo, lo devo ammettere. Però preferisco procedere così perché dai nostri errori possiamo imparare di più che dalle noiose spiegazioni.<br />
<br />
Riuscite a capire dove stia il problema? I messaggi del compilatore sono molto simili a quelli precedenti e i pallini rossi dovrebbero aiutarvi.<br />
<br />
Ci siete arrivati?<br />
<br />
Ebbene sì, il problema è proprio quello: anche ''setNome()'' e ''getNome()'' sono privati; non li possiamo usare liberamente in ''main()''.<br />
<br />
<br/>Se la cosa vi lascia sbalestrati, lo capisco: fin’ora avevamo sempre parlato di variabili private, ma mai di funzioni private. Eppure il C++ è fatto così: non dà niente per scontato. Se inserite i vostri metodi in un’area di una ''class'' che è dichiarata ‘private’, anche loro saranno protetti dall’esterno.<br />
<br />
Se pensate che non ha senso avere una funzione privata, vi sbagliate: vedrete che ne incontreremo; però ammetto che la maggior parte sono pubbliche.<br />
<br />
<br/>Comunque la soluzione consiste nel tornare ad usare l’istruzione ‘public’:<br />
<pre>class Robot{<br />
string nome;<br />
<br />
public:<br />
void setNome(string battezza) { nome = battezza; }<br />
<br />
string getNome() { return nome; }<br />
};</pre><br />
Adesso tutto compila liberamente e il risultato è quello atteso.<br />
<br />
<br />
<br />
== Piccola digressione sulle scelte di programmazione ==<br />
<br />
Cerchiamo di aggiungerci le proprietà che abbiamo usato nel JS:<br />
<pre>int carica;<br />
int x;<br />
int y;</pre><br />
Gestire questi valori è davvero semplice, ma il nostro problema sarà che al momento non abbiamo a disposizione nulla di equivalente alla comoda interfaccia HTML per dialogare con l’utente, perciò dovremo arrangiarci con il testo. L’effetto sarà molto meno accattivante.<br />
<br />
Un buon risultato da ottenere potrebbe essere una scritta riepilogativa del tipo:<br />
<pre>Robottino: 'nome robottino'<br />
posizione: x = 0, y = 0<br />
carica residua: 100%</pre><br />
<br/>Teniamo di conto che non abbiamo una posizione fissa sullo schermo dove far apparire questa scritta, perciò essa si ripeterà tutte le volte che faremo muovere il robottino. Questa sarà la massima interazione che otterremo per ora con l’utente, visto che non vogliamo dedicarci chissà quanto all’interfaccia a caratteri perché con le librerie Qt torneremo ad avere caselle di testo e pulsanti.<br />
<br />
<br/>Anche per ricevere i comandi dall’utente non abbiamo chissà quali scelte. La cosa più semplice è dargli la possibilità di digitare qualcosa alla tastiera e premere invio. A quel punto ‘decifreremo’ il suo comando e agiremo di conseguenza.<br />
<br />
Per ricevere comandi dalla tastiera, forse ve ne ricorderete, è prevista la parola magica ''cin'', che un po’, diciamo, l’opposto di ''cout'': prende i valori in ingresso e li inserisce in una variabile:<br />
<pre>string valore_in_ingresso;<br />
cin >> valore_in_ingresso;</pre><br />
Prima l’avevamo usata per gestire degli int, ma il concetto non cambia. A questo punto possiamo decidere che l’utente può premere ‘a’ per far andare il robottino a sinistra, ‘w’ per farlo andare in alto, ‘s’ per destra e ‘z’ per basso.<br />
<br />
Questo può essere gestito da una serie di if:<br />
<pre>if ( valore_in_ingresso == “a” ) …<br />
if ( valore_in_ingresso == “w”) …<br />
if ( valore_in_ingresso == “s”) …<br />
if ( valore_in_ingresso == “z”) …</pre><br />
<br />
<br />
Molti preferirebbero scrivere una sequenza di if- else.<br />
<br />
Il blocco di codice che inizia con else è quello che viene eseguito quando la condizione if è falsa. In altre parole:<br />
<br />
<pre>if (condizione) {<br />
→ se ‘condizione’ è vera, esegue questo codice<br />
}<br />
else {<br />
→ se ‘condizione’ è falsa, non si esegue il codice sopra, ma questo sì!<br />
}</pre><br />
<br />
<br />
Nel nostro caso avremmo quindi potuto scrivere:<br />
<br />
<pre>if ( valore_in_ingresso == “a”) {<br />
…<br />
}<br />
else if ( valore_in_ingresso == “w”) {<br />
…<br />
}<br />
else if ( valore_in_ingresso == “s”) {<br />
…<br />
}<br />
else if ( valore_in_ingresso == “z”) {<br />
…<br />
}</pre><br />
Prima di proseguire, guardate con attenzione i due blocchi di codice e cercate di vedere se ci sono vantaggi o svantaggi.<br />
<br />
<br/>Beh, il primo non si può definire errato, ma il secondo è più logico.<br />
<br />
Immaginate di essere un computer e di dover eseguire il codice. Mettiamo che l’utente abbia digitato “a”. Quando arrivate al primo ''if'', scoprite che la condizione è vera, pertanto eseguite il blocco di codice. Finito il blocco, proseguite con l’istruzione successiva, che è un altro ''if'', che dovete verificare per scoprire che è falso; di conseguenza, saltate alla riga dopo il blocco, che però è ancora un ''if'', che di nuovo dovete valutare come falso…<br />
<br />
Insomma, la cosa migliore sarebbe se, una volta eseguito uno degli ''if'', visto che gli altri sono in alternativa, non ne dovreste considerare più nemmeno uno.<br />
<br />
<br/>Se scrivete il codice come una sequenza di ''if''-''else'', consentite al computer di comportarsi così (nel caso l’utente digiti una “a”):<br />
<br />
*leggo il primo ''if''<nowiki>; scopro che è </nowiki>vero, perciò eseguo il codice;<br />
*vado alla riga successiva; scopro che è un ''else'', pertanto, avendo io eseguito il blocco ''if'', so già che la posso saltare, perché una condizione non può essere vera e falsa contemporaneamente!<br />
*tutti gli ''if'' successivi erano contenuti nel blocco ''else'', quindi non li vedo nemmeno – per me è come se non esistessero: vado direttamente alla riga successiva all’ultimo ''else if''.<br />
<br />
Se può aiutare, i seguenti schemi, con tutte le pecche della mia scarsa attitudine alla grafica, vorrebbero aiutare a visualizzare le differenze. Nel primo le frecce dovrebbero sottolineare come il computer sia costretto a tornare a valutare ogni singola condizione:<br />
<br />
<br/>[[File:Qt IV if-else 01.png|Qt_IV_if-else_01.png]]<br />
<br />
<br/>Nel secondo invece si mostra che soltanto nella peggiore delle ipotesi le condizioni vengono valutate tutte, mentre nella migliore ne viene valutata una sola:<br />
<br />
<br/>[[File:Qt IV if-else 02.png|Qt_IV_if-else_02.png]]<br />
<br />
<br/>Si può quindi concludere che quando abbiamo una serie di condizioni da valutare, se usiamo la seconda strada e spostiamo all’inizio quelle più probabili, forse il nostro programma sarà di qualche millesimo di secondo più veloce&nbsp;:-)<br />
<br />
Scherzi a parte, nel caso il codice da eseguire sia veramente tanto, anche le piccole ottimizzazioni possono portare qualche vantaggio.<br />
<br />
L’argomento comunque non riguarda tanto il C++ quanto la programmazione in generale, per cui ora lo lasciamo e torniamo alla nostra ''class''.<br />
<br />
== Creiamo le condizioni iniziali ==<br />
<br />
Riassumendo: abbiamo bisogno di metodi che modifichino le proprietà ‘x’, ‘y’ e ‘carica’ quando si ‘muove’ il robottino; inoltre abbiamo bisogno di un metodo che riepiloghi questi dati a schermo; poi abbiamo bisogno anche di un metodo che chieda all’utente verso dove vuole spostare il robottino e provveda a fare ciò che l’utente chiede.<br />
<br />
<br/>Cominciamo:<br />
<pre>void vaiSu()<br />
{<br />
y += 1;<br />
carica -= 5;<br />
}</pre><br />
Questo non era difficile. Con lo stesso criterio possiamo scrivere vaiDx(), vaiSx(), vaiGiu().<br />
<br />
Per riepilogare i dati a schermo, si potrebbe pensare a una funzione su per giù come questa:<br />
<pre>void datiASchermo()<br />
{<br />
cout << "Robottino '" << nome << "':" << endl;<br />
cout << " posizione: x = " << x << ", y = " << y << endl;<br />
cout << " carica residua: " << carica << "%" << endl;<br />
cout << endl << endl;<br />
}</pre><br />
Come vi sembra? Guardiamola assieme.<br />
<br />
La prima riga, supponendo che il contenuto della proprietà ‘nome’ sia “Mario” dovrebbe mandate a schermo (''cout''):<br />
<pre>Robottino 'Mario':</pre><br />
Il secondo rigo, supponendo che ‘x’ sia ancora 0 e ‘y’ sia ancora 0, dovrebbe scrivere:<br />
<pre> posizione x = 0, y = 0;</pre><br />
Guardate bene il codice e ditemi se ci trovate qualcosa che non va, perché, ve l’annuncio fin d’ora, ci aspetta una sorpresa.<br />
<br />
La terza riga dovrebbe far comparire a schermo il valore di ‘carica’; quindi, quando ‘carica’ è 100:<br />
<pre> carica residua: 100%</pre><br />
Bene. La sorpresa …non dovrebbe essere una sorpresa&nbsp;:-)<br />
<br />
‘x’ e ‘y’ non sono altro che variabili, pure locali a un blocco di codice (una ''class''), perciò, come regola del C++ il loro valore '''non''' è inizializzato: ossia, contengono dei valori binari a caso, che quasi mai saranno pari a 0. Lo stesso si può dire di ‘carica’, che noi vogliamo pari a 100 quando il robottino ‘nasce’.<br />
<br />
<br/>L’unica maniera di ottenere questo risultato è scrivere, da qualche parte del codice:<br />
<pre>x = 0;<br />
y = 0;<br />
carica = 100;</pre><br />
Ma in quale punto del codice? Perché il nostro problema è che noi vogliamo che tutti i robottini nascano così. Quindi deve essere qualcosa che succede in automatico, non appena il robottino viene creato con una scritta del tipo:<br />
<pre>Robot rbt;</pre><br />
Esisterà un modo per farlo? Voglio dire, le class sono blocchi di codice con funzioni e variabili, perciò non saremo mica i primi che hanno bisogno che il loro oggetto nasca con le variabili già impostate a determinati valori! Sarà previsto un meccanismo per farlo.<br />
<br />
Beh, certo, esiste, e a dire il vero non è un argomento che possiamo evitare di trattare. Però lo possiamo rimandare di qualche altro rigo e analizzare un paio di metodi sostitutivi i cui difetti ci consentono di capire fin da subito quanto è comodo il sistema ‘vero’.<br />
<br />
<br/>La prima cosa che potremmo pensare di fare è inizializzare le nostre variabili al momento della nascita:<br />
<pre>class Robot {<br />
int x = 0;<br />
int y = 0;<br />
int carica = 100;</pre><br />
Se ci fa fatica scrivere tanti righi, possiamo risparmiare un po’ di tempo:<br />
<pre>int x = 0, y = 0, carica = 100;</pre><br />
Con quest’ultima grafia, tutte le variabili fino al punto e virgola prendono il tipo che è specificato all’inizio, ossia diventano tutte int. Se avessimo scritto:<br />
<pre>string testo1, testo2, testo3;</pre><br />
avremmo creato tre variabili di tipo string, indipendentemente dal nome che avessimo dato alle variabili. L’importante è ricordarsi di mettere una virgola tra l’una e l’altra, perché il punto e virgola serve per chiudere l’istruzione.<br />
<br />
<br/>Questo sistema per inizializzare le variabili di una ''class'' è molto comodo e intuitivo, ma dovremmo sempre cercare di ragionare in stile C++. Se la classe non l’avessimo scritta noi, ma ci trovassimo a usare quella scritta da qualcun altro, con il divieto di modificarla perché serve anche ad altri ancora, cosa penseremmo di questo codice?<br />
<br />
Che cosa succederebbe se avessimo necessità di far nascere un robottino in un punto diverso dal centro della stanza, ossia da x = 0, y = 0? Come potremmo fare? Se lo spostassimo subito, grazie ai metodi di spostamento che abbiamo visto prima, influenzeremmo anche la ‘carica’, che risulterebbe più bassa di 100.<br />
<br />
Altrimenti dovremmo scrivere una funzione apposita, tipo ''spostaSenzaToccareLaCarica(int valoreX, int valoreY)'':<br />
<pre>void spostaSenzaToccareLaCarica(int valoreX, int valoreY)<br />
{<br />
x = valoreX;<br />
y = valoreY;<br />
}</pre><br />
e poi potremmo usarlo in un modo simile a questo:<br />
<pre>int main()<br />
{<br />
Robot rbt;<br />
rbt.spostaSenzaToccareLaCarica(3, 5);<br />
<br />
…</pre><br />
Ciò potrebbe essere tollerato dagli altri, visto che una funzione in più non dà noia se non la si usa, ma implica aver la possibilità dimettere le mani nel codice scritto da qualcun altro, cosa che non sempre è possibile – tanto per fare un esempio noi useremo gli oggetti che ci verranno messi a disposizione dalle librerie Qt, ma non avremo modo di modificarli!<br />
<br />
<br/>Comunque sia, questa idea di scrivere una funzione apposita non sembra male. Non sarebbe una cattiva idea se le classi fossero pensate con un metodo ‘universale’, una sorta di ''statoIniziale()'', che consentisse di impostare tutte le variabili al valore con cui si vuole che stiano al momento in cui l’oggetto viene creato. Una sorta di funzione che si auto invoca quando l’oggetto viene creato.<br />
<br />
<br/>In altre parole, a noi farebbe comodo una funzione del tipo:<br />
<pre>void statoIniziale(int valoreX, int valoreY, int valoreCarica)<br />
{<br />
x = valoreX;<br />
y = valoreY;<br />
carica = valoreCarica;<br />
}</pre><br />
solo che vorremmo che fosse invocata in automatico quando scriviamo:<br />
<pre>Robot rbt;</pre><br />
invece di dover scrivere:<br />
<pre>rbt.statoIniziale(0, 0, 100);</pre><br />
Sarà possibile ottenere qualcosa del genere?<br />
<br />
Come dicevo, è possibile, ma prima di arrivarci diamo un’occhiata anche a un altro sistema, tanto scomodo quanto quello di inizializzare tutte le proprietà al momento della dichiarazione. Ciò che faremo ora, infatti, sarà impostare il valore delle variabili all’interno di un altro metodo che sappiamo per certo che sarà invocato.<br />
<br />
<br/>Lo ‘stampo’ che abbiamo concepito per creare robottini, la nostra ''class'', prevede infatti che, per riconoscere un robottino dall’altro, si dia subito loro un nome. Pertanto fin da subito l’utente invocherà il metodo ''setNome(string battezza)'', e noi possiamo profittare di questo fatto per inserirci il nostro codice di ‘inizializzazione’ delle proprietà:<br />
<pre>class Robot{<br />
<br />
…<br />
<br />
public:<br />
void setNome(string battezza)<br />
{<br />
nome = battezza;<br />
x = 0;<br />
y = 0;<br />
carica = 100;<br />
}<br />
<br />
…<br />
<br />
};</pre><br />
Anche questo sistema sembra molto semplice e indolore, ma non ci vuole molto a intuire che non è universale: come potremmo mai usarlo con quegli oggetti per i quali non è prevista alcuna operazione iniziale?<br />
<br />
Ossia, se non possiamo essere sicuri al mille per mille che chi userà la nostra ''class'' invocherà come prima cosa un certo metodo, non sappiamo più dove infilare il codice che inizializza le proprietà.<br />
<br />
<br/>Per ora lasciamo il codice lì. Quel che sappiamo è che, dopo che avremo scritto:<br />
<pre>int main()<br />
{<br />
Robot rbt;<br />
rbt.setNome("Mario");<br />
…</pre><br />
le nostre proprietà conterranno valori scelti da noi e non spazzatura.<br />
<br />
Torniamo al metodo che stavamo scrivendo prima di questa lunga digressione:<br />
<pre>void datiASchermo()<br />
{<br />
cout << "Robottino '" << nome << "':" << endl;<br />
cout << " posizione: x = " << x << ", y = " << y << endl;<br />
cout << " carica residua: " << carica << "%" << endl;<br />
cout << endl << endl;<br />
}</pre><br />
Adesso magari pensiamo che funzionerà, visto che dopo<br />
<pre>rbt.setNome("Mario");</pre><br />
‘x’ sarà diventata 0, ‘y’ invece pure e ‘carica’ sarà 100…<br />
<br />
E infatti funzionerà&nbsp;:)<br />
<br />
<br />
<br />
== Un’occhiata al codice ==<br />
<br />
Penso che non ne possiate più di codice scritto a bocconcini e vogliate dare una prima occhiata complessiva al nostro programmino, perciò eccolo qui:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
class Robot{<br />
string nome;<br />
int carica;<br />
int x;<br />
int y;<br />
<br />
public:<br />
void setNome(string battezza)<br />
{<br />
nome = battezza;<br />
x = 0;<br />
y = 0;<br />
carica = 100;<br />
}<br />
<br />
string getNome() { return nome; }<br />
<br />
void vaiSu()<br />
{<br />
y += 1;<br />
carica -= 5;<br />
}<br />
<br />
void vaiGiu()<br />
{<br />
y -= 1;<br />
carica -= 5;<br />
}<br />
<br />
void vaiSx()<br />
{<br />
x -= 1;<br />
carica -= 5;<br />
}<br />
<br />
void vaiDx()<br />
{<br />
x += 1;<br />
carica -= 5;<br />
}<br />
<br />
void datiASchermo()<br />
{<br />
cout << "Robottino '" << nome << "':" << endl;<br />
cout << " posizione: x = " << x << ", y = " << y << endl;<br />
cout << " carica residua: " << carica << "%" << endl;<br />
cout << endl << endl;<br />
}<br />
};<br />
<br />
int muoviRobot(Robot &rbt);<br />
<br />
int main()<br />
{<br />
Robot rbt;<br />
rbt.setNome("Mario");<br />
<br />
while(muoviRobot(rbt))<br />
rbt.datiASchermo();<br />
<br />
return 0;<br />
}<br />
<br />
int muoviRobot(Robot &rbt)<br />
{<br />
string testo;<br />
cout << "Direzione? ";<br />
cin >> testo;<br />
<br />
if("a" == testo) {<br />
rbt.vaiSx();<br />
return 1;<br />
} else if ("w" == testo) {<br />
rbt.vaiSu();<br />
return 1;<br />
} else if ("s" == testo) {<br />
rbt.vaiDx();<br />
return 1;<br />
} else if ("z" == testo) {<br />
rbt.vaiGiu();<br />
return 1;<br />
} else if ("0" == testo) {<br />
return 0;<br />
}<br />
return 2; // 2 == tasto non riconosciuto<br />
}</pre><br />
Nella prima parte non ci dovrebbe essere nulla di strano: la class Robot è composta dal codice che si è discusso fino a qui. Invece le funzioni main() e muoviRobot() potrebbero non essere del tutto chiare alla prima occhiata, per cui ce ne occuperemo subito.<br />
<br />
<br/>La funzione ''muoviRobot()'' si occupa di chiedere all’utente di digitare del testo, nello specifico una singola lettera (‘a’, oppure ‘w’ o ‘s’ o ‘z’), seguita ovviamente dal tasto INVIO, dopodiché invoca il metodo del ''Robot'' che ‘sposta’ virtualmente l’immaginario robottino nella direzione desiderata.<br />
<br />
<br/>Dopo aver creato una variabile di tipo ''string'' denominata ‘testo’, la funzione scrive a schermo la parola “Direzione?” (''cout << "Direzione? ";'').<br />
<br />
La risposta dell’utente viene inserita nella variabile ‘testo’ (''cin >> testo;'').<br />
<br />
Il contenuto di questa variabile viene poi controllato da una serie di ''if-else'', ma la discussione su questo punto l’abbiamo già svolta prima.<br />
<br />
<br/>Guardiamo insieme come è stata pensata la logica dei valori di ritorno.<br />
<br />
Se la funzione è in grado di capire cosa vuole l’utente – che significa: se il contenuto della variabile ‘testo’ è a, w, s o z – allora la funzione restituisce 1.<br />
<br />
Se l’utente sceglie di uscire digitando “0”, allora la funzione restituisce 0.<br />
<br />
In tutti gli altri casi, restituisce 2.<br />
<br />
<br/>Ricordiamoci che quando il flusso di esecuzione dei comandi incontra un’istruzione ''return'', la funzione viene chiusa e il flusso ritorna al codice chiamante.<br />
<br />
<br/>Diamo un’occhiata anche a ''main()''.<br />
<br />
Le prime due istruzioni le abbiamo viste all’inizio di questa sezione del tutorial e non credo si debba tornarci sopra. Invece il blocco<br />
<pre>while(muoviRobot(rbt))<br />
rbt.datiASchermo();</pre><br />
può lasciare un po’ interdetti.<br />
<br />
L’istruzione<br />
<pre>while(muoviRobot(rbt))</pre><br />
significa: “finché muoviRobot ( rbt ) è vero…”<br />
<br />
Si è già detto che si usa considerare zero come falso, e tutto ciò che non è zero come vero. Perciò la stessa istruzione avrebbe potuto essere scritta così:<br />
<pre>while( 0&nbsp;!= muoviRobot(rbt) )</pre><br />
e avrebbe significato esattamente la stessa cosa (ne avevamo già parlato, ricordate?).<br />
<br />
A sua volta la funzione ''muoviRobot()'' restituisce 0 solo quando l’utente digita “0”, altrimenti restituisce o 1 o 2 – e quindi valori diversi da zero.<br />
<br />
La conclusione è che<br />
<pre>finché l’utente non digita zero…</pre><br />
si esegue il blocco di codice while.<br />
<br />
<br/>Il blocco di codice che segue è composto da una sola riga e in questi casi il C++ ci autorizza a non chiuderlo tra parentesi graffe.<br />
<br />
Quindi questo codice:<br />
<pre>while(muoviRobot(rbt))<br />
rbt.datiASchermo();</pre><br />
è assolutamente identico a questo:<br />
<pre>while(muoviRobot(rbt))<br />
{<br />
rbt.datiASchermo();<br />
}</pre><br />
Il motivo per cui non ho usato le parentesi graffe è solo dovuto al fatto che è lecito, nel C++, non usarle se tutto il codice che segue un for o un if o uno while o simili è composto da una sola riga. È lecito non significa che è consigliato. Anzi! Bisogna stare bene attenti che il nostro codice sia sempre leggibile con chiarezza.<br />
<br />
<br/>Cosa dice questo blocco di codice?<br />
<pre>finché muoviRobot() non restituisce 0, continua a chiamare il metodo datiASchermo() del robottino ‘rbt’.</pre><br />
In questa maniera si fa ‘muovere’ il robot e si comunica la posizione e la carica residua all’utente.<br />
<br />
<br/>Vorrei evidenziare, a chi non l’avesse notato, l’uso del ''reference'' per l’argomento della funzione ''muoviRobot()''. Come vedete non c’è nessuna differenza fra un oggetto creato da noi e uno di quelli che il C++ ci fornisce già pronti, come ''string'' (a parte, ovviamente, la qualità del prodotto); come non c’è differenza nella sintassi con cui si usano gli oggetti o le variabili ‘normali’.<br />
<br />
Di un oggetto si può creare un alias tramite un ''reference'' e con questa tecnica può essere modificato dalla funzione a cui viene passato. Se riguardate il tutorial precedente, vedrete che la sintassi usata lì è identica a questa sia per l’argomento che per il parametro. Possiamo quindi stare tranquilli che i metodi invocati da ''muoviRobot()'' sono proprio quelli del robottino ‘rbt’ creato in ''main()'' e la progressiva diminuzione del valore di ‘carica’ ce lo conferma.<br />
<br />
<br/>Non male: abbiamo creato il nostro primo ‘stampo per oggetti’ nel C++ (una ''class'') e un primo oggetto… e tutto pare funzionare!<br />
<br />
Adesso non ci resta che migliorarlo.<br />
<br />
<br/>Prima però, l’ultima cosa noiosa: un parolone.<br />
<br />
== Il parolone degli oggetti ==<br />
<br />
Lo abbiamo già detto all’inizio della sezione, ma non fa male ripeterlo. Una ''class'' è uno stampo per creare oggetti di un certo tipo (nel nostro esempio, robottini immaginari). Ciò implica che di suo '''non''' è un oggetto.<br />
<br />
Invece ‘rbt’ era l’oggetto creato con lo stampo ''class Robot''.<br />
<br />
<br/>Allora mettiamoci d’accordo su questa parola: creare un oggetto tramite il suo stampo si dice ''istanziare'' un oggetto.<br />
<br />
Una variabile come ‘rbt’ si definisce una ''istanza'' della ''class Robot''.<br />
<br />
<br/>Brutto ‘istanziare’, vero? Beh, anche a essere teneri, non c’è modo di considerarlo meno che orrendo. Sarà una mia fissa, ma anche in questo caso l’assonanza con l’inglese ''instance'' (che vuol dire ‘esempio’, ‘caso’) mi fa sospettare che esista un qualche segreto dell’essere informatici che non ho ancora capito, tipo dover giurare che mai e poi mai si farà uso di un vocabolario nella propria vita.<br />
<br />
Il problema di questo neologismo è che in italiano già esisteva la parola istanza e con un significato mille miglia lontano da ciò di cui stiamo parlando (chi non ha mai sentito parlare delle istanze sociali o di una istanza a una Pubblica Amministrazione?). Di conseguenza può non essere sempre semplice, quando si sente parlare di una istanza di classe, capire se si discuta delle pressanti esigenze di un ceto sociale o di un blocco di codice in C++, ma dovremo farcene una ragione.<br />
<br />
<br/>Infatti l’uso è invalso, perciò ci dobbiamo adattare al fatto che ''un esempio di un tipo'' debba divenire ''un’istanza di una classe''… E non pensiamoci più.<br />
<br />
<br />
<br />
== Il costruttore ==<br />
<br />
Abbiamo lasciato una domanda in sospeso.<br />
<br />
Se una ''class'' è un blocco di codice con delle variabili e questo blocco funziona come ‘stampo’ per creare oggetti, è possibile fare in modo che le variabili contenute in quel blocco nascano con un determinato valore iniziale non appena si crea l’oggetto?<br />
<br />
<br />
<br />
=== Ci serve un metodo ===<br />
<br />
Sì, è possibile, il sistema è semplice e non c’è più motivo per girarci intorno.<br />
<br />
In buona sostanza le cose stanno così: esiste una funzione, o meglio un metodo, visto che stiamo parlando di ''class'', che si auto invoca quando l’oggetto viene creato (''istanziato'').<br />
<br />
<br/>Questo metodo che si auto invoca può quindi essere usato per tutte le operazioni che vogliamo che il nostro oggetto compia alla nascita.<br />
<br />
Dirò di più: questo metodo, come tutte le funzioni, può prevedere degli argomenti, perciò è possibile personalizzare la nascita di ogni singolo oggetto anche quando stiamo usando sempre la stessa ''class''.<br />
<br />
<br/>A questo punto vi domanderete: ma se le cose erano così semplici, perché non ce l’ha detto subito, questo fessacchiotto?<br />
<br />
Perché l’argomento è semplice, ma ha una particolarità che merita due righe di spiegazione: il nome di questo metodo è un po’ strano.<br />
<br />
<br/>Qualcuno di voi, facendo caso al titolo di questo capitolo, potrebbe pensare che il nome in questione sia ''costruttore()'', magari all’inglese: ''constructor()''. E ci avrebbe azzeccato a metà! Infatti ci si rivolge a questo metodo come al ‘costruttore’ della ''class'', ma non è il suo nome vero, bensì un termine generico, anche se tecnico, che deriva dal suo ruolo.<br />
<br />
In realtà questo metodo costruttore non ha un vero e proprio nome, o per meglio dire: il suo nome cambia di ''class'' in ''class''. Il costruttore di ''string'' non ha lo stesso nome del costruttore di ''vector'' e anche noi dovremo scegliere con molta cura il nome del costruttore della nostra ''class Robot'', perché il C++ è molto, molto pignolo in questa faccenda!<br />
<br />
<br/>Riuscite a indovinare quale nome potremo dare a questo metodo che si auto invoca quando si istanzia un oggetto? Beh, ovviamente lo stesso nome della ''class''!<br />
<pre>class Robot{<br />
string nome;<br />
int carica;<br />
int x;<br />
int y;<br />
<br />
public:<br />
Robot();<br />
<br />
void setNome(string battezza)<br />
{<br />
…</pre><br />
Eccolo lì! Quel<br />
<pre>Robot();</pre><br />
è il nostro costruttore. Essendo il costruttore di Robot, il suo nome è Robot(). Se adesso decidessimo di costruire uno ‘stampo’ per un oggetto ‘OggettoCheNonSoBeneCosaSia’, dentro il suo blocco di codice ci sarà posto per una funzione OggettoCheNonSoBeneCosaSia(); questa funzione sarà il costruttore della classe.<br />
<pre>class OggettoCheNonSoBeneCosaSia {<br />
OggettoCheNonSoBeneCosaSia();<br />
}</pre><br />
Proviamo a riscrivere la nostra classe spostando il codice di inizializzazione delle proprietà dalla funzione setNome() al metodo costruttore Robot():<br />
<pre>Robot()<br />
{<br />
x = 0;<br />
y = 0;<br />
carica = 100;<br />
}</pre><br />
A questo punto la funzione setNome() rimarrà:<br />
<pre>void setNome(string battezza) { nome = battezza; }</pre><br />
Possiamo provare a far girare il programma per verificare che tutto funzioni come prima.<br />
<br />
<br />
<br />
=== Cambiamo argomenti ===<br />
<br />
Guardiamo un po’ più a fondo il nostro costruttore. Nel JS abbiamo visto che per creare un oggetto potevamo usare una funzione prototipo, detta anche ''constructor function'', che accettava parametri:<br />
<pre>function Robottino (pa_nome) {<br />
var nome = pa_nome;</pre><br />
In quel momento non ci era sembrato nulla di strano: le funzioni possono avere argomenti, si sa. Passando al C++, quello che può apparire un po’ forzato è invece che tramite il metodo costruttore riusciamo a passare parametri alla class.<br />
<br />
Guardiamolo da un altro punto di vista. Le nostre variabili ‘x’, ‘y’ e ‘carica’ vengono impostate agli stessi valori per tutti i robottini. La proprietà ‘nome’ invece no: sarà diversa per ogni robottino.<br />
<br />
Sarebbe possibile impostarla al valore desiderato fin dalla nascita e senza stare a invocare un metodo scritto a tale scopo? Sì, certo: è possibile tramite il costruttore.<br />
<br />
Si deve aggiungere un argomento di tipo ''string'' al costruttore in modo che questo possa ricevere il nome che si desidera dare al robottino e lo possa inserire nella variabile ‘nome’.<br />
<br />
Ma se il costruttore si auto invoca, qual è la sintassi per passargli i parametri?<br />
<br />
<br/>In effetti è stata creata una sintassi specifica per questo problema: in pratica si passano i parametri direttamente alla classe e questi verranno recapitati agli argomenti del costruttore.<br />
<br />
Nel nostro caso, se modifichiamo il costruttore ''Robot()'' in questo modo:<br />
<pre>Robot(string pa_nome)<br />
{<br />
nome = pa_nome;<br />
x = 0;<br />
y = 0;<br />
carica = 100;<br />
}</pre><br />
possiamo anche sostituire le prime righe di main() da così:<br />
<pre>int main()<br />
{<br />
Robot rbt;<br />
rbt.setNome("Mario");</pre><br />
a così:<br />
<pre>int main()<br />
{<br />
Robot rbt("Mario");</pre><br />
ottenendo esattamente lo stesso risultato.<br />
<br />
<br/>In pratica il parametro che passiamo al momento della creazione dell’oggetto (non ce la faccio proprio a dire istanziazione, mi fa male al fegato) viene spedito pari pari al costruttore.<br />
<br />
Quindi sarà accettato solo se corrisponde a quello previsto dal costruttore – il ché vorrebbe dire, nel nostro caso, che un’istruzione del tipo:<br />
<pre>Robot rbt(5);</pre><br />
darebbe un errore, perché nel costruttore è specificato che l’argomento è una string, pertanto il compilatore non ci consentirà di inserire un int.<br />
<br />
<br/>Se vogliamo, possiamo guardare le cose anche alla rovescia e dire che una ''class'', grazie al suo costruttore, è in grado di accettare parametri. Da un punto di vista concettuale non è errato e la sintassi pensata allo scopo conduce proprio a questa conclusione: infatti i parametri vengono passati direttamente alla ''class''.<br />
<br />
Si può anche arrivare a dire che creare un oggetto è all'incirca come invocare il metodo costruttore della ''class'' di quell’oggetto… Tutte affermazioni all’atto pratico non sbagliate che servono solo per ricordarsi meglio cosa succede quando si usa una certa sintassi.<br />
<br />
<br/>Quindi: una ''class'' non è una funzione; quando si scrive il relativo codice, non abbiamo una parentesi tonda prima della graffa dove inserire gli argomenti che vorremmo usare – Sull’altro lato della medaglia, però, scopriamo che: una ''class'' prevede un metodo costruttore che ha il suo stesso identico nome (comprese maiuscole e minuscole!); il metodo accetta argomenti; i parametri per tali argomenti possono essere passati al momento della creazione dell’oggetto con una sintassi che ricorda quella delle funzioni.<br />
<br />
In base a tale sintassi potremmo discutere all’infinito se stiamo, da un punto di vista concettuale, stiamo passando i parametri alla ''class'' (che non li prevede) o al costruttore della ''class'' (che non è una dichiarazione di tipo): ciò che conta è che ci ricordiamo come si fa.<br />
<br />
<br />
<br />
=== E se non voglio il costruttore? ===<br />
<br />
Qualcuno potrebbe domandarsi in quali casi convenga aggiungere un costruttore alla classe.<br />
<br />
In altre parole: conviene iniziare a scrivere una ''class'' '''senza''' il costruttore e poi magari aggiungercelo all’esigenza, o conviene partire dal presupposto che una ''class'' dovrebbe avere il suo bel costruttore?<br />
<br />
<br/>A titolo personale ritengo che sia meglio specificare fin da subito un costruttore. In fondo, se sul momento non abbiamo un compito specifico da fargli svolgere, basta scrivere un rigo che si limita a ripetere il nome della classe, ci aggiunge un paio di parentesi tonde, un punto e virgola e fine.<br />
<pre>class Qualsiasi{<br />
…<br />
public:<br />
Qualsiasi();<br />
…<br />
<br />
}</pre><br />
Questo tipo di costruttore si chiama costruttore di default. Non è una grossa incombenza. Quando poi capita di dover modificare la class e fargli fare qualcosa, è lì pronto che ci aspetta.<br />
<br />
<br/>Se però faceste la stessa domanda al compilatore, beh, è probabile che otterreste una risposta del tutto diversa: infatti dal suo punto di vista nel C++ una ''class'' '''deve''' avere il costruttore. Non può esistere una ''class'' senza il costruttore.<br />
<br />
Infatti, se non ce lo mettiamo noi… deve aggiungercelo lui!<br />
<br />
Una delle comodità dei compilatori è che, se incappano in una ''class'' senza il costruttore, al momento della trasformazione in linguaggio macchina ce lo aggiungono loro. Quindi, nel codice scritto da noi non c’era, ma nel programma eseguito dal pc sì: ce l’aveva aggiunto il compilatore.<br />
<br />
È ovvio che i compilatori aggiungono il codice di un ''costruttore di default'', ossia l’equivalente di quello che avremmo ottenuto scrivendo:<br />
<pre>Robot();</pre><br />
Questo costruttore si chiama implicit default constructor. Implicit può essere tradotto implicito, sottinteso, ma anche tacito o addirittura assoluto; in questo caso mi sembra che sottinteso sia il significato che più si avvicina all’originale.<br />
<br />
<br/>Se avessimo costruito la ''class'' usando la procedura assistita fornita da Qt Creator, ci saremmo trovati con il nostro bel costruttore, magari vuoto, inserito nel codice della classe. Poiché il costruttore è utile, infatti, gli IDE ci aiutano a non dimenticarcene.<br />
<br />
Se adesso state pensando: “Uh, che bello! Allora non starò mai a scrivere un costruttore, tanto ce lo inserisce il compilatore in automatico”, mi sento di obiettare subito: idea discutibile.<br />
<br />
Quando userete la classe di qualcun altro, vi farà piacere che ci sia un costruttore; impariamo a inserircelo anche noi.<br />
<br />
Queste piccole fatiche non ci dovrebbero scoraggiare, perché nel C++ sono previste bestioline ancora più ostiche come i costruttori in copia e i costruttori di spostamento, che non siamo obbligati a trattare ora perché nelle librerie Qt li troveremo già pronti e impacchettati.<br />
<br />
Anche il costruttore in copia, se non lo scriviamo noi, viene aggiunto nel codice eseguibile dal compilatore, quindi per ora lo ignoreremo.<br />
<br />
<br />
<br />
=== Ma guarda che tipo! ===<br />
<br />
Scommetto che pensate che me ne sia dimenticato, vero?<br />
<br />
Ebbene, no: il costruttore è fatto proprio così: non ha un valore di ritorno.<br />
<br />
Si tratta dell’unica eccezione alla regola che per tutte le funzioni si debba indicare il valore di ritorno, e se non restituiscono nulla vada scritto ''void''.<br />
<br />
<br/>Quindi, se per ''main()'' è sempre ''int'', cascasse il mondo, per un costruttore non è mai indicato alcun tipo di ritorno. Tutte le altre funzioni restituiscono il valore che piace di chi le scrive.<br />
<br />
<br/>Se vi chiedete come mai sia stata scelta questa particolare sintassi, quando sarebbe stato possibile stabilire di dichiarare tutti i costruttori ''void'' e non creare altre eccezioni nella regola generale delle funzioni, vi confesso che non lo so. Cercando su Internet forse una storia di come si sia giunti a questa decisione si potrebbe trovare, ma ancora non mi ci sono dedicato.<br />
<br />
Qui su due piedi vorrei però spezzare una lancia a suo favore, perché non è illogica. Un costruttore da chi viene invocato? In realtà da nessuno, in quanto che è chiamato direttamente dal compilatore quando deve costruire un’istanza di una ''class''. Come dicevamo all’inizio per semplificare, si auto invoca.<br />
<br />
Ma allora, se non è invocato da nessuno, a chi dovrebbe restituire il suo valore di ritorno? Sempre a nessuno. Quindi è logico che non lo abbia. Almeno mi sembra.<br />
<br />
<br/>Il costruttore è un metodo particolare, che ha un nome speciale, viene eseguito '''sempre''' (al momento della creazione dell’oggetto), ma '''una volta sola''', e poi, si può dire, esaurisce il suo compito: non è possibile invocarlo direttamente dal programma.<br />
<br />
<br/>E lo stesso si può dire, in modo speculare, per il suo fratello gemello: il distruttore.<br />
<br />
<br />
<br />
== Il distruttore ==<br />
<br />
Beh, a sentirlo nominare c’è da aver paura. Il “distruttore”. Sembra un cattivone della Marvel.<br />
<br />
<br/>Innanzitutto è bene sfatare il mito: distruttore in realtà sarebbe una congrua traduzione per la parola inglese ''destroyer'' (che, per curiosità, indica anche un tipo di nave, il cacciatorpediniere). In questo caso, invece, stiamo trattando un tema che in quella lingua si definisce ''destructor'', e nella nostra potremmo più propriamente rendere con inceneritore. Altre oscure ragioni che possano trasformare nella mente degli informatici un inceneritore in un distruttore, eccetto l’assonanza con l’originale inglese, non ne trovo. Pertanto m’impegno fin da ora a cercare il testo del giuramento formale di non far mai uso di un vocabolario, pena la scomunica, che viene con ogni evidenza firmato col sangue da tutti gli informatici.<br />
<br />
<br/>In realtà si tratta di una funzione utilissima in certe situazioni, ma non sempre usata. Il suo compito è quello di garantire che la cancellazione dell’oggetto dalla memoria, quando non serve più, avvenga con tutti i crismi. V’immaginate se, in un programma molto grande, non si riuscisse via via a liberare la memoria dagli oggetti che non servono più? In poco tempo il computer sarebbe costretto a innalzare bandiera bianca. E di programmi molto, molto grandi con il C++ ne sono stati scritti parecchi. Per fortuna, come abbiamo già visto, via via che le funzioni finiscono, le variabili, e quindi anche gli oggetti, creati localmente vengono rimossi.<br />
<br />
Il problema è che un oggetto può essere grosso e complicato. Non guardate il nostro, che ha poche variabili e pochissime funzioni: pensate a un ''vector'', che può contenere una mole impressionante di dati, e forse non è nemmeno fra gli oggetti più complessi.<br />
<br />
<br/>Quando il computer decide di cancellare un oggetto, può trovarsi davanti a un bel compito. Di solito ce la fa benissimo da solo, ma in alcuni casi conviene cercare di aiutarlo. Per farlo, possiamo inserire del codice apposito nel metodo ''destructor''<nowiki>; </nowiki>infatti, quando deve eliminare un oggetto, il computer va a leggere cosa c’è scritto nel ''destructor'' e lo esegue.<br />
<br />
Il ''destructor'' è quindi l’inceneritore che serve per smaltire in modo corretto gli oggetti che non servono più.<br />
<br />
<br/>Il nostro oggetto è molto semplice e il computer non ha bisogno di aiuto per incenerirlo, ma per capire come funziona un distruttore possiamo provare a scriverci del codice dentro e a vedere cosa succede.<br />
<br />
<br/>Cominciamo col dargli un nome; non possiamo mica chiamarlo ‘distruttore’, vi pare?<br />
<br />
Beh, qui il C++ ci viene in aiuto: infatti il ''destructor'' accetta di essere chiamato solo come il costruttore, ossia con lo stesso nome della classe. Per farsi riconoscere rispetto al costruttore, però, chiede di essere contrassegnato da un simbolo particolare: la tilde ‘~’. La tilde è un segno che non compare nella lingua italiana, ma in molte altre sì: tanto per fare degli esempi, nella spagnola e nella portoghese. Anche in matematica ha dei significati.<br />
<br />
Nel C++ serve solo a questo: a distinguere il costruttore dal ''destructor''. Quindi, nel nostro caso il ''destructor'' sarà:<br />
<pre>~Robot();</pre><br />
Per fare la tilde, non essendo presente nella tastiera italiana, potete usare uno dei seguenti metodi:<br />
<br />
*in '''Linux''' c’è una combinazione di tasti apposita: Alt Gr + ì (Alt Gr è il tasto alla destra della barra spaziatrice; la ì accentata si trova invece in alto, alla destra del punto interrogativo);<br />
*in '''Mac Os X''' la combinazione dovrebbe essere Alt + 5 (non ho il Mac, quindi sto riportando quanto si trova su Internet);<br />
*in '''Windows''' le cose sono, ma chi l’avrebbe mai detto?, più complicate: se avete il tastierino numerico, allora, tenendo premuto il tasto ALT, digitate 126; se non avete il tastierino numerico, provate a guardare se sulla vostra tastiera compaiono dei caratteri piccoli di colore azzurro; se ci sono, tenendo premuto ALT + fn, digitate 126 tramite quei caratteri azzurri. Se non funziona… mandate una mail sig. Gates.<br />
<br />
Che codice potremmo mai inserire nel nostro ''destructor''? Beh, visto che l’incenerimento del nostro oggetto ‘rbt’ è dovuto all’uscita da ''main()'', e quindi alla fine del programma, potremmo lasciare dei saluti:<br />
<pre>~Robot()<br />
{<br />
cout << endl << endl;<br />
cout << "Torna presto a trovarci!" << endl << endl;<br />
}</pre><br />
Aggiungete il metodo precedente in un punto qualsiasi della class Robot –ma non all’interno di una altro metodo!– e state a guardare cosa succede quando il programma termina.<br />
<br />
<br/>[[File:Qt IV 09.png|Qt_IV_09.png]]<br />
<br />
<br/>Il nostro educato robottino saluta prima di sparire.<br />
<br />
<br/>Bene, abbiamo fatto la conoscenza anche con il ''destructor'', che presenta le stesse caratteristiche del costruttore:<br />
<br />
*non si può invocare direttamente;<br />
*viene sempre chiamato direttamente dal computer quando un oggetto viene eliminato;<br />
*viene chiamato una volta sola;<br />
*ha lo stesso nome della ''class'', ma preceduto da tilde;<br />
*non ammette valori di ritorno.<br />
<br />
Questo è il riepilogo delle modifiche:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
class Robot{<br />
string nome;<br />
int carica;<br />
int x;<br />
int y;<br />
<br />
public:<br />
Robot(string pa_nome)<br />
{<br />
nome = pa_nome;<br />
x = 0;<br />
y = 0;<br />
carica = 100;<br />
}<br />
<br />
void setNome(string battezza) {nome = battezza;}<br />
<br />
string getNome() { return nome; }<br />
<br />
void vaiSu()<br />
{<br />
y += 1;<br />
carica -= 5;<br />
}<br />
<br />
void vaiGiu()<br />
{<br />
y -= 1;<br />
carica -= 5;<br />
}<br />
<br />
void vaiSx()<br />
{<br />
x -= 1;<br />
carica -= 5;<br />
}<br />
<br />
void vaiDx()<br />
{<br />
x += 1;<br />
carica -= 5;<br />
}<br />
<br />
void datiASchermo()<br />
{<br />
cout << "Robottino '" << nome << "':" << endl;<br />
cout << " posizione: x = " << x << ", y = " << y << endl;<br />
cout << " carica residua: " << carica << "%" << endl;<br />
cout << endl << endl;<br />
}<br />
<br />
~Robot()<br />
{<br />
cout << endl << endl;<br />
cout << "Torna presto a trovarci!" << endl << endl;<br />
}<br />
};<br />
<br />
int muoviRobot(Robot &rbt);<br />
<br />
int main()<br />
{<br />
Robot rbt("Mario");<br />
// rbt.setNome("Mario");<br />
<br />
while(muoviRobot(rbt))<br />
rbt.datiASchermo();<br />
<br />
return 0;<br />
}<br />
<br />
int muoviRobot(Robot &rbt)<br />
{<br />
string testo;<br />
cout << "Direzione? ";<br />
cin >> testo;<br />
<br />
if("a" == testo) {<br />
rbt.vaiSx();<br />
return 1;<br />
} else if ("w" == testo) {<br />
rbt.vaiSu();<br />
return 1;<br />
} else if ("s" == testo) {<br />
rbt.vaiDx();<br />
return 1;<br />
} else if ("z" == testo) {<br />
rbt.vaiGiu();<br />
return 1;<br />
} else if ("0" == testo) {<br />
return 0;<br />
}<br />
return 2; // 2 == tasto non riconosciuto<br />
}</pre><br />
<br />
<br />
== Puntatori a oggetto ==<br />
Nel nostro programmino abbiamo usato un ''reference'' ad un oggetto (''&rbt''). Secondo voi è possibile anche avere puntatori agli oggetti?<br />
<br />
Domanda scontata?&nbsp;:)<br />
<br />
<br />
In effetti abbiamo già incontrato puntatori a ''string'' nell’ultimo tutorial e abbiamo già anticipato che la sintassi cambia leggermente: se vogliamo usare un puntatore, non possiamo raggiungere i membri dell’oggetto tramite un punto, ma dobbiamo servirci dello strano operatore ‘->’.<br />
<br />
In effetti una classe è un blocco di codice con un’etichetta, perciò non può non avere un indirizzo di memoria; quell’indirizzo di memoria è solo un numero, che può benissimo essere passato a un puntatore.<br />
<br />
<br />
La sintassi per dichiarare un puntatore a oggetto è identica a quella che abbiamo incontrato fin qui:<br />
<br />
<pre>Robot* rbt;</pre><br />
Dopodiché, come dicevo, per invocare un metodo come vaiSx(), dovremmo scrivere:<br />
<pre>rbt->vaiSx();</pre><br />
e otterremo lo stesso risultato.<br />
<br />
<br/>La domanda che a qualcuno potrebbe venire è se si possono avere dei puntatori '''all’interno''' dell’oggetto. In altre parole, una delle nostre variabili, a esempio ‘carica’, poteva essere:<br />
<pre>int* carica;</pre><br />
?<br />
<br />
Sì, certo, poteva. Una classe può contenere un po’ di tutto. Abbiamo dichiarato dei puntatori all’interno delle funzioni, poi delle funzioni all’interno di una classe… Viene abbastanza naturale supporre che un puntatore può essere dichiarato all’interno di una classe&nbsp;:-)<br />
<br />
Ricordiamoci però che, finché non lo inizializziamo, i byte che compongono il nostro puntatore contengono una sequenza ignota di cifre, perciò sta puntando ad uno spazio a caso della memoria dove può essere contenuta qualsiasi cosa. Usare un puntatore soltanto per sostituire un ''int'' di solito non è molto vantaggioso, a meno che non vogliamo accedere a quello ''int'' da diversi ''scope'', spazi di visibilità.<br />
<br />
Però… ragioniamoci un po’ su. Una variabile dichiarata all’interno di una ''class'', anche se privata, è visibile da tutte le funzioni membro di quella ''class''… Quindi, ognuna di esse può usarla come se fosse propria.<br />
<br />
<br/>Allora possiamo intanto giungere a questa conclusione: le funzioni dichiarate all’interno di una ''class'' hanno una specie di vantaggio rispetto alle funzioni ‘normali’ perché, oltre alle variabili globali e a quelle locali (compresi gli argomenti), possono vedere anche le variabili che non sono locali a loro, ma lo sono rispetto alla ''class''. Sto parlando di quelle variabili, come ‘carica’, che vengono solitamente chiamate ''proprietà'' della ''class''.<br />
<br />
<br/>Godendo di questa situazione vantaggiosa, dichiarare puntatore una proprietà di una class ci può dare dei vantaggi concreti?<br />
<br />
Non so se mi sono espresso correttamente. Il vantaggio dei puntatori è che riusciamo, come dire, a ‘muoverli’ da una funzione all’altra – giacché quello che viene copiato nell’argomento è un indirizzo, usando i puntatori riusciamo ad accedere sempre alla stessa cella di memoria, che vuol dire “allo stesso valore”, da tutte le funzioni.<br />
<br />
Ma all’interno di una ''class'' tutti metodi possono accedere alle proprietà, quindi che vantaggio ci sarebbe a farne dei puntatori?<br />
<br />
<br/>Le esigenze che nascono quando si comincia a programmare sono così tante che può capitare di scrivere e leggere di tutto; non ci sorprendiamo perciò a scoprire che i puntatori all’interno delle ''class'' sono molto usati. I loro impieghi sono molteplici, ma per ora ci basti pensare all’eventualità di voler tenere di mira qualcosa che è ''esterno'' alla classe – funzione che un puntatore può assolvere benissimo.<br />
<br />
<br/>Quale potrebbe essere la loro sintassi? Mettiamo il caso che crei una ''class'' con un puntatore – per comodità lo dichiaro ''public'', così posso evitare di scrivere metodi per usarlo (ma non è questa la logica degli oggetti!):<br />
<pre>class ACaso {<br />
public:<br />
int* puntatore;<br />
}; // ricordarsi questo punto e virgola!</pre><br />
Mettiamo che trovi un qualcosa da fargli puntare:<br />
<pre>int main()<br />
{<br />
// Creo una variabile intera con un nome e un valore a caso<br />
int intQualsiasi = 17;<br />
<br />
// Creo un oggetto tramite il mio ‘stampo’ ''class'' ACaso.<br />
ACaso acs;<br />
<br />
// Passo l’indirizzo della variabile intera definita prima <br />
// al puntatore contenuto nella mia ''class''.<br />
<br />
acs.puntatore = &intQualsiasi; // Da questo momento posso usare<br />
// acs.puntatore per accedere <br />
// al valore di intQualsiasi.<br />
}</pre><br />
Spero che il codice soprastante non crei difficoltà a nessuno. Sono tutte cose di cui abbiamo già parlato.<br />
<br />
Adesso possiamo provare a usare il nostro puntatore per accedere ai dati della variabile puntata come abbiamo sempre fatto, ossia usando l’asterisco (‘*’), che in questo caso prende il nome di ''simbolo di deferenziazione''.<br />
<pre> cout << "intQualsiasi == " << *acs.puntatore << endl << endl;</pre><br />
Il risultato è esattamente quello atteso.<br />
<br />
<br/>[[File:Qt IV 10.png|Qt_IV_10.png]]<br />
<br />
<br/>Sembra tutto a posto e in effetti lo è. Avete notato, però, dove è andato a finire il nostro simbolo di dereferenziazione?<br />
<pre>*acs.puntatore</pre><br />
Si è spostato prima del nome della variabile che rappresenta l’istanza della classe. Questa è una nuova sintassi da imparare: non è nomevariabile-punto-asterisco-nomepuntatore, ma asterisco-nomevariabile-punto-nomepuntatore.<br />
<br />
Se provate a scrivere<br />
<pre>acs.*puntatore</pre><br />
vi dà errore.<br />
<br />
Adesso però proviamo a trasformare il codice di main da così<br />
<pre>int main()<br />
{<br />
// Creo una variabile intera con un nome e un valore a caso<br />
int intQualsiasi = 17;<br />
<br />
// Creo un oggetto tramite il mio ‘stampo’ class ACaso.<br />
ACaso acs;<br />
<br />
// Passo l’indirizzo della variabile intera definita prima<br />
// al puntatore contenuto nella mia class.<br />
<br />
acs.puntatore = &intQualsiasi; // Da questo momento posso usare<br />
// acs.puntatore per accedere<br />
// al valore di intQualsiasi.<br />
cout << "intQualsiasi == " << *acs.puntatore << endl << endl;<br />
}</pre><br />
a così<br />
<pre>int main()<br />
{<br />
// Creo una variabile intera con un nome e un valore a caso<br />
int intQualsiasi = 17;<br />
<br />
// Creo un oggetto tramite il mio ‘stampo’ class ACaso.<br />
ACaso* acs;<br />
…</pre><br />
Quindi trasformando ‘acs’ in un puntatore. Prima di andare avanti, soffermiamoci su cosa stiamo facendo.<br />
<br />
Se vi ricordate la lunga spiegazione del tutorial precedente, vi verrà il dubbio di scoprire se il nostro puntatore sta puntando a un’area di memoria che contiene qualche dato utile oppure no. La risposta è: ovviamente no. Il puntatore appena creato contiene come valore un numero intero casuale, che soltanto una volta ogni innumerevoli tentativi corrisponderà all’indirizzo di una cella di memoria che contiene dei dati salvati da noi.<br />
<br />
Infatti noi abbiamo detto al compilatore solo questo: “crea un puntatore che sia idoneo a puntare a un’area di memoria che contenga un’istanza della ''class'' ACaso”. Non abbiamo creato '''nessuna''' istanza della ''class'' ACaso.<br />
<br />
Per fare in modo che il nostro puntatore sia connesso a una vera istanza della classe ACaso, dobbiamo crearla e poi passare il suo indirizzo al puntatore:<br />
<pre>ACaso acs;<br />
ACaso* p_acs = &acs;</pre><br />
Ci sarebbe un metodo più breve, che fa uso della parola magica “new”, ma ancora non ne abbiamo parlato perciò non possiamo adottarlo.<br />
<br />
Tornando al nostro codice, ora abbiamo un puntatore a una classe (ACaso) che ha tra i suoi membri una proprietà che è un puntatore:<br />
<pre>int* puntatore;</pre><br />
Adesso diciamo a ‘puntatore’ di tenere di mira la variabile locale intQualsiasi:<br />
<pre>p_acs->puntatore = &intQualsiasi;</pre><br />
La sintassi è cambiata. Avevamo già affrontato questo argomento, ma questo capitolo vorrebbe provare a dare una spiegazione di questo dettaglio.<br />
<br />
Dunque, detta in breve: quando la variabile che rappresenta l’istanza della classe è un puntatore, allora per accedere ai suoi membri non si usa un punto (‘.’), bensì la buffa combinazione ''trattino-maggiore di'' (‘->’).<br />
<br />
Volendo fare un esempio con la classe precedente, ''Robot'', se ne creassimo un’istanza tramite un puntatore<br />
<br />
Robot* p_rbt;<br />
<br />
dovremmo invocare i suoi membri così:<br />
<pre>p_rbt->setNome("Mario");<br />
p_rbt->datiASchermo();<br />
p_rbt->vaiSx();</pre><br />
ecc. ecc.<br />
<br />
In apparenza può sembrare una sottigliezza di cui non si sentiva il bisogno, ma se teniamo presente che ora l’asterisco che serve per accedere ai dati puntati si è spostato prima del nome della variabile che rappresenta l’istanza della classe, tutto acquista un senso.<br />
<br />
Se non ci arrivate subito, guardate un po’ cosa succede al rigo successivo:<br />
<pre>cout << "intQualsiasi == " << *p_acs->puntatore << endl << endl;</pre><br />
Cominciate a sospettare dov’è l’inghippo?<br />
<br />
Ipotizziamo che non esista la regola di usare il simbolo -> nel caso si crei un’istanza di una classe tramite un puntatore, ma si possa usare il semplice punto. Se fosse così, come andrebbe scritta l’istruzione precedente? Forse così:<br />
<pre>cout << "intQualsiasi == " << *p_acs.puntatore << endl << endl;</pre><br />
In tal caso però, provate a chiedervi: “come fa il compilatore a sapere se l’asterisco si deve riferire al puntatore ‘p_acs’ o al puntatore ‘puntatore’?” Quale dei due puntatori dovrebbe dereferenziare?<br />
<br />
La sintassi è ambigua, infatti il compilatore si blocca dandoci un errore, tra l’altro molto chiaro:<br />
<br />
<br/>[[File:Qt IV 11.png|Qt_IV_11.png]]<br />
<br />
<br/>''Maybe you meant to use ‘->’&nbsp;?'' è uno dei pochi messaggi d’errore che fornisce un aiuto immediato. Di solito, come avete visto, sono più farraginosi.<br />
<br />
Il C++ però non è cattivo come sembra: se avessimo una qualche avversione verso il simbolo ‘->’, il linguaggio ci autorizza a non usarlo. Possiamo continuare a basarci sul semplice punto, però stando attenti a dereferenziare correttamente il puntatore che rappresenta la classe:<br />
<pre>(*p_acs).puntatore</pre><br />
è una sintassi del tutto corretta e equivalente sotto ogni aspetto a<br />
<pre>p_acs->puntatore</pre><br />
Le parentesi che includono l’asterisco e il nome della variabile consento infatti al compilatore di interpretare ciò che volete, ossia dereferenziare il puntatore che tiene di mira l’istanza di classe in modo da raggiungere uno dei suoi membri, in questo caso la proprietà pubblica ‘puntatore’.<br />
<br />
Questo però non vi consente ancora di arrivare al contenuto della variabile intQualsiasi, per raggiungere il quale dovete dereferenziare anche ‘puntatore’:<br />
<pre>*(*p_acs).puntatore</pre><br />
L’ultima istruzione funziona, provare per credere:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
class ACaso {<br />
public:<br />
int* puntatore;<br />
};<br />
<br />
int main()<br />
{<br />
int intQualsiasi = 17;<br />
<br />
ACaso acs;<br />
ACaso* p_acs = &acs;<br />
<br />
p_acs->puntatore = &intQualsiasi;<br />
cout << "intQualsiasi == " << *(*p_acs).puntatore << endl << endl;<br />
}</pre><br />
Se la sintassi<br />
<pre>*(*p_acs).</pre><br />
vi sembra più chiara di<br />
<pre>*p_acs-></pre><br />
siete liberi di usarla: io mi trovo molto meglio con ‘->’, pensato proprio per semplificare la vita!<br />
<br />
<br/>Adesso però semplifichiamoci la vita fra noi: la lunga locuzione che ho usato fin qui, variabile che rappresenta un’istanza di ''class'', è veramente faticosa da scrivere e da leggere. Un’istanza di una ''class'' è un oggetto, cosicché per semplicità si estende questo termine anche alla variabile che lo rappresenta. Perciò, nel nostro esempio, ‘acs’ poteva essere chiamato semplicemente ''oggetto'' e ‘p_acs’ ''puntatore a oggetto''.<br />
<br />
D’ora innanzi così faremo, rendendo tutto molto più scorrevole.<br />
<br />
== Conclusioni ==<br />
<br />
Se qualcuno che conosce già il C++ sta scorrendo questo tutorial, nel leggere il titolo di questa sezione avrà subito un’extrasistole. Se infatti quel poco che abbiamo detto sul JS consente già di farsi un quadro di cosa sia un oggetto, nel C++ abbiamo a malapena scalfito la superficie.<br />
<br />
Se guardo la lista degli argomenti di cui dovremmo ancora parlare, mi prende male: costruttore in copia e di spostamento, ''overload'' delle funzioni e del costruttore, ''overload'' degli operatori, ereditarietà, ereditarietà multipla, funzioni virtuali, funzioni virtuali pure, ''virtual constructor'', ''virtual destructor, ''classi base astratte, ''early binding'' e ''late binding'', polimorfismo, membri ''static'', sintassi della dichiarazioni degli oggetti, ''member initializer list'', classi annidate… Per non parlar poi del successivo livello di astrazione: i ''template''!<br />
<br />
Il supporto alla programmazione agli oggetti nel C++ è davvero vasto e rappresenta uno dei suoi punti di forza.<br />
<br />
<br/>Però di tutorial sul C++ ne esistono moltissimi a giro, tutti scritti da persone più competenti di me, e aggiungerne un altro non sarebbe utile a nessuno. Siamo quindi costretti a operare delle scelte, e la nostra scelta è di saltare a piè pari tutto ciò che non è strettamente indispensabile per maneggiare le librerie Qt.<br />
<br />
Chi, forse un po’ anche per merito di questo piccolo tutorial, si fosse appassionato di questo linguaggio, sappia che online ci sono risorse molto più tecniche e complete di questa, che anzi è forse un po’ troppo discorsiva.<br />
<br />
<br/>A noi ci basta sapere che abbiamo ancora quattro argomenti enormi da trattare, che ci porteranno via ancora un sacco di tempo, per cui di tutto il resto non abbiamo proprio modo di occuparcene:<br />
<br />
#che cosa significa “using namespace std”;<br />
#che cos’è ''this'' (nel C++);<br />
#come si fa a scrivere una classe su più file;<br />
#cosa fa la parola magica ''new''.<br />
<br />
Tutti questi argomenti sono connessi in qualche modo agli oggetti, alcuni in modo intimo (''this''), altri più alla lontana (''using namespace std''), pertanto li abbiamo rimandati fino a qui, ma ora non possiamo più evitarli.<br />
<br />
<br />
<br />
= using namespace std: liberiamocene! =<br />
<br />
Dovete sapere che il professor Stroustrup è anche il curatore di un sito sul C++ che rappresenta uno dei punti di riferimento di chi vuole muovere i primi passi in questo linguaggio.<br />
<br />
L’indirizzo del sito è il seguente:<br />
<br />
[http://www.stroustrup.com/bs_faq2.html http://www.stroustrup.com/bs_faq2.html]<br />
<br />
In seguito il contenuto di questa pagina web è stato, come minimo in buona parte, inglobato in quest’altro sito:<br />
<br />
[http://isocpp.org/faq http://isocpp.org/faq]<br />
<br />
<br/>Purtroppo queste due risorse sono entrambe in inglese, ma la loro utilità, per chi è interessato a una spiegazione esaustiva e molto chiara su tanti argomenti, è indiscutibile. Comunque sia, uno degli argomenti trattati su questo sito è: «Dovrei o no usare l’istruzione ''using namespace std'' nel mio codice?» E la risposta è: «Probabilmente no.»<br />
<br />
La trovate qui:<br />
<br />
[http://isocpp.org/wiki/faq/coding-standards#using-namespace-std http://isocpp.org/wiki/faq/coding-standards#using-namespace-std]<br />
<br />
<br/>A questo punto potete capire quanto mi senta in colpa ad avervela fatta usare così tanto, ma la realtà è che, per programmi piccoli come i nostri, questa istruzione è del tutto innocua. Adesso però possiamo riuscire a sbarazzarcene.<br />
<br />
Dobbiamo però capire cos’è un ''namespace''.<br />
<br />
<br/>Anche in questo caso, la risposta alla domanda è una diretta conseguenza del dubbio che assale molti di fronte alle tante sfaccettature del linguaggio C++: perché mai dovremmo spendere tanta fatica a imparare un singolo linguaggio di programmazione?<br />
<br />
In effetti la risposta che mi viene è sempre la stessa: è un linguaggio che presenta un sacco di strumenti utili a chi vuole lavorare in squadra. La possibilità di collaborare in tanti a un unico progetto senza pestarsi i calli è un vantaggio non da poco quando si devono scrivere programmi molto ricchi e complessi.<br />
<br />
I ''namespace'' fanno parte di quei preziosi strumenti di collaborazione.<br />
<br />
<br/>Abbiamo visto che in linea generale non dobbiamo preoccuparci molto dei nomi che diamo alle variabili, tant’è che nella maggior parte dei programmi vediamo comparire con una prevedibilità più che rispettabile un ristretto insieme di nomi: ‘i’ per le variabili di tipo ''int'', ‘l’ per quelle ''long'', ‘d’ e ‘f’ per due tipi che ancora non abbiamo visto, i ''double'' e i ''float'', ‘u’ per gli ''unsigned int'' e ‘s’ per ''string'' o similari. Quasi con la stessa frequenza troviamo ‘v’ per ''vector'' e ‘counter’ per una variabile che viene usata per registrare la quantità di una qualche cosa.<br />
<br />
Il vantaggio dei nomi di una sola lettera è che sono ovviamente molto veloci da scrivere, perciò non fanno perdere tempo quando si deve buttare giù il codice. Nonostante la stragrande maggioranza dei programmatori abusi di questi nomi, il C++ garantisce che il nome scelto da uno dei collaboratori di un progetto non interferisca con quello scelto da un altro grazie al principio dello ''scope'': se una variabile è locale a un pezzo di codice, il suo nome non crea ambiguità con quello contenuto in altri pezzi di codice.<br />
<br />
Il che vuol dire: finché io mi occupo delle mie funzioni e delle mie classi, non creo disturbo a te che stai usando gli stessi ‘i’, ‘u’, ‘s’ e così via nelle tue funzioni e nelle tue classi.<br />
<br />
<br/>Ho specificato funzioni e classi perché il discorso può cambiare se prendiamo come esempio altre parti del codice. Cosa succede per esempio quando uno di noi si trova nella necessità di dichiarare una variabile globale?<br />
<br />
<br/>Se ve ne ricordate, anche in questo caso ''come regola generale'' potremmo anche non essere a conoscenza del fatto. Infatti anche in questa situazione il C++, tramite il ''mascheramento'' dei nomi di variabile, ci consente di lavorare sulle nostre variabili senza interferire con quelle globali.<br />
<br />
<br/>Nota: vi ricordate cos’è il maschermento, vero? Se esiste una variabile globale che si chiama ‘valore Importante’, ma '''all’interno di una funzione''' io creo un’altra variabile<br />
<pre>int valoreImportante;</pre><br />
d’ora innanzi, quando userò il nome ‘valoreImportante’ il compilatore farà riferimento alla variabile locale, non a quella globale.<br />
<br />
Se voglio fare riferimento a quella globale devo usare il simbolo ‘::’ in questo modo:<br />
<pre>::valoreImportante = 5 // la variabile *globale* valoreImportante<br />
// è stata portata a 5</pre><br />
Fine della nota.<br />
<br />
<br/>Tutto parrebbe sotto controllo, quindi, ma il fatto che ne parliamo già vi sta facendo sospettare che qualcosa che potrebbe non funzionare come un orologio svizzero potrebbe saltare fuori…<br />
<br />
E avete ragione&nbsp;;-)<br />
<br />
<br/>Mettiamo che a un certo punto io, non sapendo che voi avevate già scritto la ''class'' Robot, decida di scrivere un codice come questo:<br />
<pre>class Robot{<br />
…<br />
}</pre><br />
oppure come questo:<br />
<pre>struct Robot{<br />
…<br />
}</pre><br />
Vi ricordate cos’è una struct, vero? È come una class, ma i membri sono pubblici di default.<br />
<br />
Cosa succederebbe secondo voi in questo caso?<br />
<br />
Purtroppo le regole del mascheramento in questa situazione potrebbero non essere applicabili. Infatti chi scrive un blocco di codice lungo e complicato come quello di una ''class'' di solito lo fa perché ha bisogno di usarlo come stampo per creare più oggetti, qua e là nel codice, perciò vuole che il nome della classe sia visibile un po’ ovunque – abbia cioè uno ''scope'' globale.<br />
<br />
<br/>Questo può facilmente diventare un problema in quei software sviluppati da grandi aziende dove lavorano decine o centinaia di programmatori, la maggior parte dei quali, come dicevamo, tende a usare nomi semplici che si ricordano e si digitano con facilità – e di conseguenza sono spesso gli stessi.<br />
<br />
<br/>Ma anche noi potremmo trovarci nei problemi!<br />
<br />
Vi può sembrare un’eventualità un po’ remota, visto che fin’ora siamo riusciti a scrivere solo un programmino con una singola ''class'', ma non avete considerato un altro aspetto: all’inizio dei nostri programmi inseriamo sempre la scritta<br />
<pre>#include <iostream></pre><br />
Dopo quella riga, tutto ciò che è contenuto nel file “iostream” viene copiato nel nostro codice.<br />
<br />
Siamo sicuri di essere a conoscenza di tutti i nomi che sono contenuti lì, in modo da non duplicarli?<br />
<br />
E se includiamo “vector”? E “string”? Oppure qualcuno degli altri, per i quali, se vi interessa, posso fornire una lista:<br />
<br />
<br />
<br />
{| class="wikitable"<br />
|-<br />
| &lt;cassert&gt;<br />
| &lt;array&gt;<br />
| &lt;atomic&gt;<br />
| &lt;algorithm&gt;<br />
|-<br />
| &lt;cctype&gt;<br />
| &lt;bitset&gt;<br />
| &lt;condition_variable&gt;<br />
| &lt;chrono&gt;<br />
|-<br />
| &lt;cerrno&gt;<br />
| &lt;deque&gt;<br />
| &lt;future&gt;<br />
| &lt;codecvt&gt;<br />
|-<br />
| &lt;cfenv&gt;<br />
| &lt;forward_list&gt;<br />
| &lt;mutex&gt;<br />
| &lt;complex&gt;<br />
|-<br />
| &lt;cfloat&gt;<br />
| &lt;list&gt;<br />
| &lt;thread&gt;<br />
| &lt;exception&gt;<br />
|-<br />
| &lt;cinttypes&gt;<br />
| &lt;map&gt;<br />
| <br />
| &lt;functional&gt;<br />
|-<br />
| &lt;ciso646&gt;<br />
| &lt;queue&gt;<br />
| <br />
| &lt;initializer_list&gt;<br />
|-<br />
| &lt;climits&gt;<br />
| &lt;set&gt;<br />
| <br />
| &lt;iterator&gt;<br />
|-<br />
| &lt;clocale&gt;<br />
| &lt;stack&gt;<br />
| <br />
| &lt;limits&gt;<br />
|-<br />
| &lt;cmath&gt;<br />
| &lt;unordered_map&gt;<br />
| <br />
| &lt;locale&gt;<br />
|-<br />
| &lt;csetjmp&gt;<br />
| &lt;unordered_set&gt;<br />
| <br />
| &lt;memory&gt;<br />
|-<br />
| &lt;csignal&gt;<br />
| &lt;vector&gt;<br />
| <br />
| &lt;new&gt;<br />
|-<br />
| &lt;cstdarg&gt;<br />
| <br />
| <br />
| &lt;numeric&gt;<br />
|-<br />
| &lt;cstdbool&gt;<br />
| <br />
| <br />
| &lt;random&gt;<br />
|-<br />
| &lt;cstddef&gt;<br />
| <br />
| <br />
| &lt;ratio&gt;<br />
|-<br />
| &lt;cstdint&gt;<br />
| <br />
| <br />
| &lt;regex&gt;<br />
|-<br />
| &lt;cstdio&gt;<br />
| <br />
| <br />
| &lt;stdexcept&gt;<br />
|-<br />
| &lt;cstdlib&gt;<br />
| <br />
| <br />
| &lt;string&gt;<br />
|-<br />
| &lt;cstring&gt;<br />
| <br />
| <br />
| &lt;system_error&gt;<br />
|-<br />
| &lt;ctgmath&gt;<br />
| <br />
| <br />
| &lt;tuple&gt;<br />
|-<br />
| &lt;ctime&gt;<br />
| <br />
| <br />
| &lt;typeindex&gt;<br />
|-<br />
| &lt;cuchar&gt;<br />
| <br />
| <br />
| &lt;typeinfo&gt;<br />
|-<br />
| &lt;cwchar&gt;<br />
| <br />
| <br />
| &lt;type_traits&gt;<br />
|-<br />
| &lt;cwctype&gt;<br />
| <br />
| <br />
| &lt;utility&gt;<br />
|-<br />
| <br />
| <br />
| <br />
| &lt;valarray&gt;<br />
|}<br />
<br />
<br/>Che ne dite? C’è una qualche possibilità che uno dei nomi lì dichiarati possa entrare in conflitto con uno dichiarato da noi? Per quanto rara, la possibilità c’è. Ma il C++ offre una soluzione anche per questo, e la soluzione sono i ''namespace''.<br />
<br />
<br/>La sintassi dei ''namespace'' è semplice, ma ci interessa di più capirne il meccanismo.<br />
<br />
In pratica un ''namespace'' non fa altro che dichiarare un nuovo nome. Tutto ciò che creiamo da quel momento in poi, se vogliamo possiamo includerlo in quel nome. In questa maniera, per far riferimento a ciò che abbiamo creato, dovremo dare due nomi e non più uno solo: il nome del ''namespace'' e quello del nostro blocco di codice.<br />
<br />
<br/>Un esempio renderà tutto più chiaro.<br />
<br />
Mettiamo il caso che stiamo tutti lavorando sullo stesso progetto. Siamo autorizzati a dichiarare classi, funzioni e quant’altro a nostro piacimento. Per non interferire l’uno con il lavoro dell’altro, scegliamo di assegnarci un ''namespace'' ciascuno, partendo dai rispettivi nomi e cognomi.<br />
<br />
Il nostro collega Stanislao Moulinsky sceglie per sé il ''namespace'' “stan”.<br />
<br />
A questo punto, se la classe Robot l’avesse creata lui, avrebbe dovuto dichiararla così:<br />
<pre>namespace stan{<br />
class Robot{<br />
… // tutto il codice della classe<br />
};<br />
}</pre><br />
Come vedete non c’è niente di scioccante: la nostra classe viene semplicemente ‘inglobata’ in un ulteriore copia di parentesi graffe; prima di questa parentesi viene scritta la parola namespace e un’altra parola a nostra scelta che sarà il nome del nostro namespace.<br />
<br />
<br/>A questo punto il nome della ''class'' “Robot” è sparito: non è più visibile dal resto del codice. L’unica maniera per arrivarci è dire al compilatore: «La ''class'' “Robot” che è stata dichiarata all’interno del ''namespace'' “stan”.»<br />
<br />
Il simbolo per “entrare dentro” un ''namespace'' lo abbiamo già visto in un’altra occasione: è il simbolo di ''scope resolution'' ‘::’.<br />
<br />
Quindi per arrivare a “Robot” d’ora in avanti si dovrà scrivere<br />
<pre>stan::Robot</pre><br />
Vediamo un po’ come funziona nella pratica.<br />
<br />
La nostra istruzione:<br />
<pre>Robot rbt("Mario");</pre><br />
dovrà diventare:<br />
<pre>stan::Robot rbt("Mario");</pre><br />
mentre<br />
<pre>int muoviRobot(Robot &rbt)</pre><br />
ora sarà:<br />
<pre>int muoviRobot(stan::Robot &rbt)</pre><br />
Potete provare ad apportare queste piccole modifiche e a verificare che il programma funzioni come prima.<br />
<br />
In sostanza ciò che abbiamo ottenuto è che, se anche Goffredo avesse creato una ''class'' “Robot”, ma l’avesse inglobata in un ''namespace'' “goff”, o con qualsiasi altro nome, non correremmo il rischio di creare un oggetto partendo dallo stampo sbagliato.<br />
<br />
O meglio: il programma compilerebbe lo stesso. Infatti non si arriva mai a domandarsi se ci siano due classi con lo stesso nome perché, o almeno una delle due è stata inglobata in un ''namespace'', oppure il compilatore si rifiuta di proseguire. La regola è che non si può usare due volte lo stesso nome nello stesso spazio di visibilità, di qualsiasi cosa stiamo parlando.<br />
<br />
<br/>Quando sono state progettate le librerie standard, ossia quelle che vengono fornite insieme a ogni compilatore, come a esempio i file “iostream” e “vector” che abbiamo già usato, si è cercato di eliminare la possibilità di conflitti fra i vari nomi.<br />
<br />
Si è perciò studiato un modo per fare in modo che i programmatori potessero usare i nomi che volevano per le loro classi e funzioni senza doversi preoccupare di eventuali conflitti nel momento in cui includevano i files della libreria standard. Per ottenere questo risultato, '''tutti i nomi contenuti nelle librerie standard sono stati inglobati nel ''namespace'' “std”'''.<br />
<br />
<br/>Ciò significa che né ''vector'', né ''string'', né ''cout'' né nessun altro degli oggetti che abbiamo già usato sarebbe di per sé visibile dal compilatore semplicemente a seguito dell’istruzione ''<nowiki>#include <fileDellaLibreriaStandard></nowiki>'', bensì ciascuno di essi avrebbe dovuto essere preceduto dall’istruzione ''std::''<br />
<pre>std::vector miovector;<br />
std::cout << "Testo a schermo" << std::endl;<br />
std::string testo = "Testo a caso";</pre><br />
Questa sintassi è la più sicura, nel senso che è quella con cui si corre il rischio di commettere meno errori. Ha però uno svantaggio: è un po’ scomoda!<br />
<br />
Noi perciò abbiamo deciso di liberarci del problema sfruttando l’istruzione ''using'', la quale introduce in modo permanente nello psazio di visibilità in cui ci si trova dei nomi che di per sé si troverebbero nascosti dentro un ''namespace''. Quando abbiamo scritto<br />
<pre>using namespace std;<br />
<br />
''</pre><br />
abbiamo detto al compilatore di includere l’intero namespace “std” nel nostro programma, ossia di darci libero accesso ai nomi contenuti in quel namespace senza che dovessimo specificare std::<br />
<br />
Attenzione! Questo '''non''' significa che sono state incluse le istruzioni relative a quei nomi, ossia tutte le righe di codice che fanno funzionare a esempio un ''vector'', perché quello è compito dell’istruzione ''<nowiki>#include</nowiki>'', ma solo che abbiamo potuto accedere senza limitazioni ai nomi.<br />
<br />
<br/>Se pensate che siamo stati molto furbi, non mi trovate d’accordo. Siamo al contrario stati poco previdenti. Infatti ci saremmo dovuti garantire di conoscere a menadito le librerie standard prima di fare in modo che il nostro codice potesse entrare in conflitto con uno dei nomi lì esistenti.<br />
<br />
A dire il vero il rischio era basso finché abbiamo continuato a scegliere, per le nostre funzioni e variabili, dei nomi in italiano: infatti non esiste alcuna parola italiana fra i nomi delle librerie standard!<br />
<br />
Adesso però, venuti a conoscenza del pericolo e saputo che alcuni tra i massimi esperti mondiali di C++ disapprovano la nostra scelta, non possiamo proseguire così.<br />
<br />
<br/>Questo significa forse che dovremo cominciare a scrivere sempre ''std::string'', ''std::cout'' e così via? Beh, la risposta sincera sarebbe che i bravi bambini farebbero così.<br />
<br />
Per quelli un po’ discoli come sono sempre stato io&nbsp;:-) esiste una sintassi di compromesso:<br />
<pre>using singolo_nome_che_si_vuole_usare_nel_programma;</pre><br />
In pratica si può elencare, all’inizio del nostro codice, i nomi che vogliamo usare, ma che sono nascosti in dei namespace, e il compilatore ci farà accedere a quei nomi lasciando però ‘nascosti’ gli altri.<br />
<br />
Ossia, dopo che ho scritto una volta:<br />
<pre>using std::cout;<br />
using std::endl;<br />
using std::string;</pre><br />
da quel punto in poi potremo usare cout, endl e string come se avessimo scritto using namespace std. Conviene quindi scriverlo all’inizio del programma:<br />
<pre>#include <iostream><br />
<br />
using std::cin;<br />
using std::cout;<br />
using std::endl;<br />
using std::string;<br />
<br />
namespace stan{<br />
class Robot{<br />
string nome;<br />
int carica;<br />
int x;<br />
int y;<br />
<br />
public:<br />
Robot(string pa_nome)<br />
{<br />
nome = pa_nome;<br />
x = 0;<br />
y = 0;<br />
carica = 100;<br />
}<br />
<br />
void setNome(string battezza) {nome = battezza;}<br />
<br />
string getNome() { return nome; }<br />
<br />
void vaiSu()<br />
{<br />
y += 1;<br />
carica -= 5;<br />
}<br />
<br />
void vaiGiu()<br />
{<br />
y -= 1;<br />
carica -= 5;<br />
}<br />
<br />
void vaiSx()<br />
{<br />
x -= 1;<br />
carica -= 5;<br />
}<br />
<br />
void vaiDx()<br />
{<br />
x += 1;<br />
carica -= 5;<br />
}<br />
<br />
void datiASchermo()<br />
{<br />
cout << "Robottino '" << nome << "':" << endl;<br />
cout << " posizione: x = " << x << ", y = " << y << endl;<br />
cout << " carica residua: " << carica << "%" << endl;<br />
cout << endl << endl;<br />
}<br />
<br />
~Robot()<br />
{<br />
cout << endl << endl;<br />
cout << "Torna presto a trovarci!" << endl << endl;<br />
}<br />
};<br />
}<br />
<br />
int muoviRobot(stan::Robot &rbt);<br />
<br />
int main()<br />
{<br />
stan::Robot rbt("Mario");<br />
// rbt.setNome("Mario");<br />
<br />
while(muoviRobot(rbt))<br />
rbt.datiASchermo();<br />
<br />
return 0;<br />
}<br />
<br />
int muoviRobot(stan::Robot &rbt)<br />
{<br />
string testo;<br />
cout << "Direzione? ";<br />
cin >> testo;<br />
<br />
if("a" == testo) {<br />
rbt.vaiSx();<br />
return 1;<br />
} else if ("w" == testo) {<br />
rbt.vaiSu();<br />
return 1;<br />
} else if ("s" == testo) {<br />
rbt.vaiDx();<br />
return 1;<br />
} else if ("z" == testo) {<br />
rbt.vaiGiu();<br />
return 1;<br />
} else if ("0" == testo) {<br />
return 0;<br />
}<br />
return 2; // 2 == tasto non riconosciuto<br />
}</pre><br />
Questa soluzione non è sicura come la sintassi raccomandata, ma per i nostri scopi è più che sufficiente. Possiamo quindi dare l’addio a using namespace std e proseguire verso altri lidi.<br />
<br />
<br />
<br />
= Is this important? =<br />
<br />
Questo è l’ultimo capitolo un pochino concettoso di questa puntata del tutorial; sia quello precedente che quelli a seguire riguardano più che altro miglioramenti al modo di approcciarsi al codice. Qui invece siamo di nuovo con le mani in pasta tra puntatori e indirizzi di memoria.<br />
<br />
<br/>Abbiamo visto la parola ''this'' comparire nel JS, ma quando abbiamo cercato di scrivere un codice equivalente nel C++, essa si è volatilizzata.<br />
<br />
In effetti nel C++ ha una funzione molto più specifica di quanto non abbia nel JS, perciò non sempre è obbligatoria. È però vero che ha un buon numero di ‘cultori’ i quali preferiscono usarla anche quando non è obbligatoria.<br />
<br />
Vediamo di capire meglio di cosa si tratta.<br />
<br />
<br/>Per scoprire cosa sia ''this'' abbiamo bisogno di una ''class'' qualsiasi, anche semplicissima. Chi non volesse perdere il codice di “Robottino” può chiudere il progetto che abbiamo usato fin qui e riaprire il buon vecchio “Prove”. L’idea non è malvagia perché nel prossimo capitolo ci servirà di nuovo “Robottino”, perciò ci può far comodo lasciarlo com’è.<br />
<br />
<br/>Per chiudere il progetto, come prima cosa chiudiamo i file aperti facendo click sulla X in alto a destra (chi usa Qt in un sistema operativo diverso da Kubuntu potrebbe trovarsi con delle finestre leggermente diverse, ma con un po’ di spirito di osservazione dovrebbe riuscire a ottenere comunque il risultato).<br />
<br />
<br/>[[File:Qt IV 12.png|Qt_IV_12.png]]<br />
<br />
<br/>Quando tutti i file sono chiusi, basta fare click destro sulla parola “Robottino”…<br />
<br />
<br/>[[File:Qt IV 13.png|Qt_IV_13.png]]<br />
<br />
<br/>…e scegliere ''Close project "Robottino"''.<br />
<br />
<br/>[[File:Qt IV 14.png|Qt_IV_14.png]]<br />
<br />
<br/>Per riaprire un progetto esistente, tornare alla schermata iniziale facendo click su “Welcome”.<br />
<br />
<br/>[[File:Qt IV 15.png|Qt_IV_15.png]]<br />
<br />
<br/>E selezionare il progetto che interessa.<br />
<br />
<br/>[[File:Qt IV 16.png|Qt_IV_16.png]]<br />
<br />
<br/>Come al solito, il nostro codice andrà nel file main.cpp.<br />
<br />
<br />
<br />
== What is this? ==<br />
<br />
Creiamo la ''class'' più piccola possibile:<br />
<pre>#include <iostream><br />
<br />
class Qualunque {};<br />
<br />
int main()<br />
{<br />
Qualunque mioOggetto;<br />
}</pre><br />
Abbiamo creato una class vuota. Meno di così, onestamente, non potevamo scrivere. A dire il vero potevamo evitare l’istruzione<br />
<pre>#include <iostream></pre><br />
ma tanto ora ci servirà, perciò…<br />
<br />
Adesso lasciamoci prendere dalla curiosità: in quale cella di memoria sarà stata inserita la nostra istanza di classe ‘mioOggetto’? Proviamo a scoprirlo:<br />
<pre>#include <iostream><br />
<br />
using std::cout;<br />
using std::endl;<br />
<br />
class Qualunque {<br />
};<br />
<br />
int main()<br />
{<br />
Qualunque mioOggetto;<br />
cout << "Indirizzo di memoria di mioOggetto: "<br />
<< (unsigned long) &mioOggetto << endl << endl;<br />
}</pre><br />
Vi ricordate il discorso di (unsigned long), vero? Serve per fare in modo che std::cout gestisca il numero che rappresenta l’indirizzo di memoria di mioOggetto nella maniera che piace a noi, ossia come un intero positivo.<br />
<br />
Adesso andiamo a curiosare su cosa sia questo ''this''.<br />
<pre>class Qualunque {<br />
public:<br />
Qualunque() { cout << (unsigned long) this << endl; }<br />
};</pre><br />
Eh, eh, eh! Questa non ve la aspettavate, dite la verità.<br />
<br />
Andiamo con calma. Prima informazione: ''this'' è un membro della ''class''. Con questo intendo dire che è un membro di '''ogni''' ''class''. Esiste nelle ''class'' senza bisogno che noi lo dichiariamo.<br />
<br />
Detto in altre parole: ogni ''class'' possiede un membro nascosto il cui nome è ''this''.<br />
<br />
<br/>Seconda informazione: se vi state chiedendo se somiglia di più a una proprietà o a un metodo, vi dico che si comporta né più né meno come una proprietà. Infatti ''this'' è definito come un '''puntatore'''.<br />
<br />
Terza informazione: se fate girare il programma, ci arrivate da soli. Questo è l’output:<br />
<br />
<br/>[[File:Qt IV 17.png|Qt_IV_17.png]]<br />
<br />
<br/>La terza informazione è quindi: ''this'' è un puntatore che tiene di mira l’indirizzo di memoria dell’oggetto, ossia dell’istanza di ''class'' che abbiamo creato.<br />
<br />
<br/>Vi si sta surriscaldando il cervello? In effetti, la prima volta che ho visto ''this'' mi sono domandato se avessi capito bene la spiegazione. A cosa diavolo potrebbe mai servire un puntatore, contenuto in un oggetto, che tiene di mira l’indirizzo di memoria dell’oggetto stesso?<br />
<br />
<br/>In effetti non è facile da cogliere, ma come ci è già successo dobbiamo scindere le due parti del problema: una cosa è capire che cos’è e una cosa è capire a cosa serve.<br />
<br />
Ora come ora a noi serve capire cos’è, e in fondo non si tratta di niente di complicato. Ci serve capire cos’è perché ci potrà capitare di incontrarlo lavorando con le librerie Qt, ma sarà molto difficile che ci troviamo costretti a usarlo.<br />
<br />
Però mi rendo conto –anche perché sono fra queste– che esistono persone che non riescono a penetrare bene un argomento se non trovano il modo di applicarlo nella pratica. Per facilitare la vita a queste persone proveremo a fare un breve discorso generale sull’uso di ''this'', ma nel caso vi rimanesse oscuro, non vi preoccupate: l’importante è che, quando lo troviamo in qualche programma, sappiamo che cos’è, altrimenti il codice ci rimarrebbe oscuro.<br />
<br />
<br />
<br />
== A cosa serve this? ==<br />
<br />
Un sacco di persone usano ''this'' per uno scopo che non è quello per cui è nato, cioè lo adoperano per rendere più leggibile il codice.<br />
<br />
Questo scopo è il più semplice da capire, per cui lo possiamo trattare per primo.<br />
<br />
Cerchiamo di ricordarci cosa abbiamo detto poco fa: un sacco di programmatori si annoiano a scrivere lunghi nomi per le variabili, perciò cercano di essere il più stringati possibile. Ecco che, nel corso degli anni, si è creata una consuetudine molto abusata:<br />
<br />
*i per una variabile di tipo ''int''<nowiki>;</nowiki><br />
*l per una variabile di tipo ''long''<nowiki>;</nowiki><br />
*d per una variabile di tipo ''double'' (non le conosciamo, ma esistono);<br />
*f per una variabile di tipo ''float'' (anche queste non le conosciamo)<nowiki>;</nowiki><br />
*s per un oggetto ''string'' (o char* → si usano molto nel C, ma molto meno nel C++, quindi può darsi che non le useremo mai!);<br />
*v per un oggetto ''vector''<nowiki>;</nowiki><br />
*c per una variabile di tipo ''char'' (va bene, nemmeno questo l’abbiamo mai visto, ma non ne sentiamo la mancanza. Attenzione! È scritto minuscolo: ‘c’. La corrispondente maiuscola si ritrova nell’istruzione “extern C”, che è tutta un’altra cosa);<br />
<br />
e magari anche altri che ora non mi vengono in mente. Negli esempi si trova spesso scritto ''f()'' per indicare una funzione, ma nel codice reale non credo nessuno lo usi.<br />
<br />
La conseguenza è che i programmi sono pieni di ‘i’, ‘v’, ‘s’… Nonostante il mascheramento, se non si sta attenti si corre il rischio di ripetere i nomi.<br />
<br />
<br/>Non capita di rado di vedere usare questi nomi così brevi anche per le proprietà delle ''class'':<br />
<pre>class Qualunque {<br />
private:<br />
int i;<br />
…</pre><br />
Magari a un certo punto ci si rende conto che il valore di quella variabile deve essere impostato dall’utente; a questo punto si scrive un metodo che accetta un parametro il cui valore viene copiato nella proprietà privata ‘i’. Indovinate un po’, in forza dell’abitudine, come viene chiamato l’argomento di quella funzione?<br />
<br />
Ma che bravi, avete proprio indovinato: sempre ‘i’.<br />
<br />
Ecco che ci troviamo di fronte a qualcosa del genere:<br />
<pre>void setValI(int i) { i = i; }</pre><br />
Carino, vero? La prima domanda che scappa è: «ma funzionerà?»<br />
<br />
Un po’ sadicamente vi lascio con la curiosità di provare: l’esercizio non è per nulla al di là delle vostre possibilità. In pratica dovete verificare se la proprietà privata ‘i’ viene valorizzata con la copia del valore dell’argomento ‘i’ oppure no. O ancora, se il compilatore vi dà errore.<br />
<br />
Noi invece proseguiamo con quella che è una possibile soluzione al problema (posto che non si voglia o possa rinominare una delle variabili in gioco!): l’uso di ''this''.<br />
<pre>void setValI(int i) { this->i = i; }</pre><br />
Ebbene sì, essendo this un puntatore, va usata la sintassi ‘->’.<br />
<br />
In questo caso l’ambiguità si risolve perché la scritta ''this->i'' garantisce che in questo caso il compilatore interpreti ‘i’ come la proprietà ‘i’ e non come l’argomento ‘i’ del metodo setValI().<br />
<br />
<br/>Riuscite a capire come mai? Proviamo a guardarlo insieme.<br />
<br />
Poniamo il caso che in ''main()'' venga dichiarato un puntatore che sia valorizzato con l’indirizzo dell’oggetto mioOggetto:<br />
<pre>Qualunque* p_mioOggetto = &mioOggetto;</pre><br />
Adesso facciamo diventare pubblica la proprietà ‘i’ e rendiamo un po’ più chiaro il codice dentro il costruttore:<br />
<pre>class Qualunque {<br />
public:<br />
int i;<br />
Qualunque()<br />
{<br />
cout << "Valore di this = " <br />
<< (unsigned long) this << endl;<br />
}<br />
};</pre><br />
A questo punto ‘i’ è visibile dall’esterno. Significa che in main() possiamo scrivere:<br />
<pre> p_mioOggetto->i = 8; // un numero a caso</pre><br />
Così facendo modifichiamo direttamente ‘i’. Adesso proviamo a fare altrettanto dentro il costruttore tramite this:<br />
<pre>this->i = 12; // un numero a caso</pre><br />
In entrambi i casi possiamo aggiungere un’istruzione che mostri il risultato delle nostre fatiche:<br />
<pre>cout << "Valore di i = " << this->i << endl;</pre><br />
Facciamo un’ultima piccola modifica al codice che ci consenta di ottenere il seguente risultato complessivo:<br />
<pre>#include <iostream><br />
<br />
using std::cout;<br />
using std::endl;<br />
<br />
class Qualunque {<br />
public:<br />
int i;<br />
Qualunque()<br />
{<br />
cout << "Valore di this = "<br />
<< (unsigned long) this << endl;<br />
this->i = 12; // un numero a caso<br />
cout << "Valore di i = " << this->i << endl;<br />
}<br />
};<br />
<br />
int main()<br />
{<br />
Qualunque mioOggetto;<br />
<br />
Qualunque* p_mioOggetto = &mioOggetto;<br />
<br />
p_mioOggetto->i = 8; // un numero a caso<br />
<br />
cout << "Valore di p_mioOggetto = "<br />
<< (unsigned long) p_mioOggetto << endl;<br />
<br />
cout << "Valore di i = "<br />
<< p_mioOggetto->i << endl << endl;<br />
}</pre><br />
Il risultato che otteniamo dovrebbe parlare da solo:<br />
<br />
<br/>[[File:Qt IV 18.png|Qt_IV_18.png]]<br />
<br />
<br/>Possiamo quindi confermare che ''this'' è l’equivalente di un puntatore al nostro oggetto che sia stato dichiarato in una funzione esterna alla classe; la differenza è che ''this'' è un membro della classe, perciò può accedere alla proprietà ‘i’ anche quando è ''private'' (mentre ‘p_mioOggetto’ non potrebbe farlo).<br />
<br />
<br/>Proseguendo il ragionamento, come un puntatore esterno alla classe può accedere ai membri pubblici dell’oggetto tramite ->, lo stesso può fare ''this''.<br />
<br />
Ma potrebbe un puntatore come ‘p_mioOggetto’ accedere a una variabile locale a una funzione della classe? Ovviamente no. E a un argomento della stessa funzione? Sempre no, perché abbiamo già detto che la distinzione fra un argomento e una variabile locale è solo nella sintassi e nel fatto che gli argomenti ricevono i valori dei parametri; per tutto il resto, un parametro è indistinguibile da una variabile locale.<br />
<br />
<br/>In conseguenza di ciò, tornando all’esempio di prima, quando scriviamo ''this->i'' siamo sicuri che il compilatore interpreta ‘i’ come proprietà della classe e non come argomento del metodo ''setValI()'' perché ''this'' non può vedere tale variabile.<br />
<br />
Non ci resta che provare:<br />
<pre>#include <iostream><br />
<br />
using std::cout;<br />
using std::endl;<br />
<br />
class Qualunque {<br />
private:<br />
int i;<br />
public:<br />
Qualunque() {}<br />
~Qualunque() { cout << "valore di i = " << i << endl << endl; }<br />
void setValI(int i) { this->i = i; }<br />
};<br />
<br />
int main()<br />
{<br />
Qualunque mioOggetto;<br />
<br />
mioOggetto.setValI(8);<br />
<br />
// All'uscita da main() vengono cancellate tutte<br />
// le variabili, pertanto anche l'oggetto mioOggetto.<br />
// Prima di rimuoverlo dalla memoria, viene invocato<br />
// il distruttore.<br />
}</pre><br />
Usando il distruttore ci siamo risparmiati di dover scrivere un metodo per mostrare a schermo il valore della variabile privata ‘i’. Se fate girare il programma, vi confermerà che this consente al compilatore di scegliere la variabile giusta.<br />
<br />
<br/>Qualcuno di voi però si starà chiedendo: «Ma era necessario perdere così tanto tempo dietro a questo esempio? Sarebbe bastato chiamare le due variabili in modo diverso –per dire, ‘i1’ per la proprietà della classe e ‘i2’ per l’argomento del metodo– che tutto sarebbe filato liscio senza tanti puntatori e complicazioni varie…»<br />
<br />
L’osservazione è verissima. Però conviene sapere che ''this'' può essere utile per cavarsi d’impaccio in certe situazioni, e una situazione può essere: quando si suppone che il compilatore possa sbagliare a scegliere una variabile. Ora cercheremo di essere più chiari, ma per adesso, riallacciandoci all’inizio del discorso, forse siamo riusciti a far apparire più chiaro il motivo per cui ''this'' ha così tanti estimatori.<br />
<br />
Alcuni programmatori infatti ritengono che si debba mettere ''this->'' di fronte a '''ogni proprietà''' di una ''class'', giacché così, sostengono, chi legge riconosce immediatamente le variabili membro della ''class'' da quelle locali. In questo modo verrebbe migliorata la leggibilità del codice.<br />
<br />
<br/>Entrare nella diatriba se sia una buona idea o no sarebbe un suicidio. Forse non ci crederete, ma in tutti i forum sul C++ prima o poi salta fuori qualcuno che ventila un metodo per scegliere i nomi per le proprietà delle ''class''.<br />
<br />
*Ci sono i sostenitori dello “m_” che sostengono che le proprietà dovrebbero tutte iniziare così, per m_. Quindi la nostra variabile ‘i’ dovrebbe diventare ‘m_i’ e, tornando a “Robot”, ‘nome’ dovrebbe girarsi in ‘m_nome’, ‘carica’ in ‘m_carica’ e così via.<br />
*Altri invece sono sostenitori della lineetta in basso (''underscore'') finale: ‘_’. Con questo metodo avremmo invece: i_, nome_, carica_…<br />
*Alcuni accettano il consiglio, ma spostano lo ''underscore'' all’inizio della parola: _i, _nome, _carica …<br />
*Altri si sposano con ''this->'' e gli rimangono fedeli fino alla fine (this->i, this->nome, this-> carica…).<br />
*Altri ancora avanzano altre proposte.<br />
<br />
Da parte nostra ci facciamo baluardo del succitato sito della Standard C++ Foundation, il quale entra con delicatezza nell’argomento alla FAQ “Which is better: identifier names that_look_like_this or identifier names thatLookLikeThis?”<br />
<br />
[http://isocpp.org/wiki/faq/coding-standards#identifier-name-conventions http://isocpp.org/wiki/faq/coding-standards#identifier-name-conventions]<br />
<br />
Il tema lì trattato è un po’ più generale di questo (si parla di tutti i nomi, non solo di quelli delle proprietà delle classi) e non voglio mettere in bocca agli autori cose che non hanno scritto. Secondo me però la conclusione è che a oggi non è stato creato un vero e proprio standard su come scegliere i nomi delle proprietà delle classi, pertanto un metodo può valere l’altro.<br />
<br />
Anche solo il caro vecchio buonsenso può essere d’aiuto. Qualcuno potrebbe per esempio proporre di evitare di usare nomi estremamente brevi per le proprietà, o comunque di non basarsi solo su quelli di una lettera.<br />
<br />
<br/>Ci tengo però a far notare che, seppure il C++ non sia il C, e anzi se ne stia distanziando sempre di più, ne è comunque uno dei figli.<br />
<br />
Se riprendiamo in mano il testo di Kernighan e Ritchie sul C, nel capitolo 2 (''Types, operators, and Expressions''), al paragrafo 2.1 (''Variable Names'') possiamo leggere: «Don’t begin variable names with underscore, however, since library routines often use such names.»<br />
<br />
Nella seconda edizione del manuale sul C++ scritto da Stroustrup, di cui purtroppo non ho la versione originale inglese, al paragrafo 3.2 si legge: «I nomi che iniziano con un carattere di sottolineatura vengono generalmente riservate a particolari funzioni dell’ambiente esecutivo, perciò non è consigliabile l’uso di tali nomi in programmi applicativi.» L’errore nomi-riservate non è mio, ma si trova nella traduzione, che è pessima. Tuttavia il significato mi sembra chiaro.<br />
<br />
<br />
<br />
== Ma, sul serio, allora a cosa serve? ==<br />
<br />
Nella stragrande maggioranza dei casi, se non mascheriamo i nomi delle proprietà della classe, non siamo obbligati a usare ''this''.<br />
<br />
Ci sono però un paio di casi in cui è indispensabile. Uno riguarda l’ereditarietà dei ''template'' e, nel caso ci dovesse interessare, ce ne occuperemo quando li incontreremo: fin qui non abbiamo parlato né dell'ereditarietà né tanto meno dei ''template'', perciò non lo affronteremo.<br />
<br />
Per chi non potesse farne a meno, segnalo l’unica pagina che ho trovato dove è spiegato nel dettaglio. La pagina è in inglese e tratta argomenti incomprensibili per coloro che conoscono del C++ solo quello di cui abbiamo parlato fin qui:<br />
<br />
[http://www.parashift.com/c++-faq-lite/nondependent-name-lookup-members.html http://www.parashift.com/c++-faq-lite/nondependent-name-lookup-members.html]<br />
<br />
<br/>Un altro caso lo troviamo nel manuale sul C++ scritto dal prof. Stroustrup, ma mi sembra un po’ complicato. Penso sia meglio se ne propongo una versione semplificata.<br />
<br />
L’esempio riguarda le cosiddette ''doubly linked lists'', che forse potremmo tradurre con una certa libertà liste a catena. Proviamo ad approcciarle partendo dai ''vector''.<br />
<br />
Abbiamo visto che un ''vector'' è una specie di contenitore che ci consente di maneggiare gruppi di oggetti purché siano tutti dello stesso tipo. Il tipo degli oggetti va indicato con cura subito dopo la parola ''vector'', fra parentesi angolari, per esempio ''vector&lt;int&gt;''.<br />
<br />
''vector'' è molto flessibile, tant’è che potremmo usarlo anche per creare una sequenza degli oggetti progettati da noi; se volessimo, tanto per dire, usare cinque dei nostri robottini insieme, potremmo dichiarare una variabile in questa maniera:<br />
<pre>vector<Robot> tantiRobot;</pre><br />
e poi aggiungerci dentro cinque “Robot”.<br />
<br />
<br/>L’accesso agli oggetti contenuti in un ''vector'' è consentito tramite un indice. Nel nostro esempio, ‘tantiRobot.at(0)’ ci consentirebbe di usare il primo robottino, ‘tantiRobot.at(1)’ il secondo e così via.<br />
<br />
Una lista di oggetti di questo genere ha come caratteristica il fatto che ogni oggetto ‘ignora’ la presenza degli altri. Poiché si può raggiungere ogni oggetto tramite un indice, nessuno degli elementi della lista viene influenzato dalla presenza degli altri.<br />
<br />
Nel caso di ‘tantiRobot’, pensiamo a esempio al robottino numero 3. Poniamo il caso che l’abbiamo chiamato Lauretta. Immaginiamoci la sequenza in orizzontale, da destra verso sinistra. L’oggetto 3 avrebbe alla sua destra l’oggetto 2, che potremmo aver chiamato Terenzio, e alla sua sinistra l’oggetto 4, mettiamo Giada. Se il robottino 3 fosse cancellato, Terenzio si troverebbe al fianco di Giada, ma nessuno di loro verrebbe nemmeno a sapere di questo cambiamento: infatti nessun dato sarebbe cambiato né in Terenzio né in Giada.<br />
<br />
<br/>Questa però non è l’unica maniera di concepire una lista di oggetti. Si può anche pensare che esistano liste in cui ogni oggetto conosce il ‘nome’ dell’oggetto che ha al fianco e per raggiungere un determinato oggetto non si può usare un indice, ma si deve per forza attraversare la lista.<br />
<br />
Avete mai partecipato a una caccia al tesoro? Sapete come funziona il gioco?<br />
<br />
Le regole sono molto semplici: un oggetto viene nascosto all’insaputa dei partecipanti. Il luogo dove si trova viene descritto in un indovinello, che viene a sua volta nascosto in un altro luogo.<br />
<br />
Anche dove trovare questo indovinello, però, è svelato da un ulteriore indovinello, a sua volta celato in un nascondiglio diverso. E così via, quante volte a piacere, finché non si decide che gli indovinelli sono un numero sufficiente. L’ultimo di questi viene passato ai concorrenti, i quali a quel punto possono iniziare la caccia. Chi arriva primo si tiene il ‘tesoro’.<br />
<br />
<br/>Dal punto di vista di chi nasconde, quello che viene consegnato ai concorrenti è l’''ultimo'' indovinello, mentre dal punto di vista di chi partecipa al gioco è il ''primo'', ma questo non cambia la sostanza: l’unica maniera per arrivare al tesoro è passare da un indovinello all’altro. Se uno degli indovinelli venisse a mancare, perché rovinato dall’umidità, portato via dal vento o che so io, non ci sarebbe modo di giungere all’oggetto successivo.<br />
<br />
Lo stesso tipo di considerazioni si potrebbe fare per una catena: gli anelli sono tutti connessi fra di loro e la catena rimane tale finché nessuno di essi si rompe; da quel momento, gli oggetti alla destra dell’anello spezzato non avrebbero più alcun legame con quelli alla sinistra.<br />
<br />
<br/>Se quindi volessimo simulare in un programma un gioco di caccia al tesoro, potremmo farlo tramite un ''vector'', ma forse non sarebbe la scelta migliore perché in teoria non dovremmo trovarci nelle condizioni di dover usare l’indice. Forse dovremmo preferirgli una ''doubly linked list'', ossia un contenitore in cui ogni oggetto contiene un riferimento, o una connessione, a quello che lo segue (e anche uno a quello che precede).<br />
<br />
<br/>Anche se fino a ora non ne avevamo parlato, sappiate che non sono per niente oggetti rari. Anzi! Se guardate i nomi dei file della libreria standard che abbiamo elencato sopra, troverete “list”. Beh, l’istruzione<br />
<pre>#include <list></pre><br />
rappresenta il primo passo per poter usare un oggetto list, che è molto simile a un vector, ma con la differenza che è progettato con il meccanismo della connessione tra gli elementi contenuti (ossia è una doubly linked list).<br />
<br />
<br/>Prendendomi la licenza di ritoccare l’esempio del prof. Stroustrup per renderlo più semplice, proverò a far vedere qual è il punto nodale di una lista a catena e in cosa ci può dare una mano ''this''.<br />
<br />
Una catena è composta di singoli anelli collegati fra di loro.<br />
<br />
Possiamo quindi provare a figurarci una ''class'' Anello che ci aiuti a riprodurre questa situazione.<br />
<pre>class Anello {<br />
…<br />
};</pre><br />
Una serie di anelli forma una catena, ma l’idea va considerata nel modo più ampio possibile. In una caccia al tesoro ogni “Anello” potrebbe rappresentare un indovinello.<br />
<br />
Quando andremo a usare la nostra ''class'' Anello, dovremo definire un’istanza per ogni Anello che ci servirà. Invece adesso, in fase di progettazione della ''class'', dovremo pensare ad un modo in cui ogni Anello possa essere ‘agganciato’ al successivo.<br />
<br />
<br/>Per collegare un anello al successivo la cosa più semplice è fornire un puntatore che tenga di mira l’Anello successivo. Se deve tenere di mira un Anello, ovviamente non può che essere un puntatore di tipo “Anello”:<br />
<pre>class Anello {<br />
private:<br />
Anello* successivo;<br />
};</pre><br />
Quest’istruzione può lasciare qualcuno un po’ interdetto. Come, all’interno di una class stiamo creando un’istanza della medesima class?!<br />
<br />
Prima di tutto, attenzione! '''Non''' stiamo creando un’istanza della ''class'' Anello, bensì '''un puntatore di tipo Anello'''.<br />
<br />
Le due cose sono ben diverse. Come ricorderete un puntatore non è altro che una variabile che contiene un numero intero; è il fatto che quel numero rappresenti un indirizzo di memoria che la rende così interessante!<br />
<br />
Il puntatore comunque non deve obbligatoriamente essere valorizzato con l’indirizzo di memoria di qualcosa fin da subito. Intanto può cominciare a esistere, seppure avendo in sé un numero casuale che ci porterebbe chissà dove.<br />
<br />
<br/>Per il compilatore tutto ciò non è un problema. Nel momento in cui dichiariamo il nostro puntatore ad Anello, lui già sa che cos’è “Anello”: è una ''class''. L’ha letto poco sopra. Per cui per lui non ci sono problemi: il puntatore può esistere.<br />
<br />
<br/>Teniamo anche conto di un altro fatto: tutto ciò che scriviamo mentre progettiamo una ''class'' rimane a livello di puro, come dire, design finché non creiamo un’istanza di quella ''class''. È l’oggetto, ossia l’istanza della ''class'', che finisce in memoria e quindi riceve un indirizzo, non la descrizione, che è solo uno stampo. Per cui per il compilatore sapere che in una istanza di una ''class'' è contenuto un puntatore che deve tenere di mira un’altra diversa istanza della stessa ''class'' non è una cosa che crei problemi.<br />
<br />
<br/>Abbiamo creato il primo passaggio della nostra ''class''. Adesso ci dobbiamo aggiungere una connessione all’Anello precedente:<br />
<pre>class Anello {<br />
private:<br />
Anello* successivo;<br />
Anello* precedente;<br />
};</pre><br />
Bene. Adesso ci serve un metodo che faccia funzionare questo codice, ossia che inserisca i valori giusti in ‘precedente’ e ‘successivo’.<br />
<br />
Prima di scriverlo cerchiamo di vedere come potrebbero procedere le cose in una funzione che voglia servirsi di questa ''class'':<br />
<pre>int main()<br />
{<br />
Anello primo;<br />
}</pre><br />
Vogliamo creare una catena, sicché un “Anello” solo non ci basta:<br />
<pre>int main()<br />
{<br />
Anello primo, secondo;<br />
}</pre><br />
Adesso vogliamo ‘collegare’ il primo “Anello” con il secondo. Ci farebbe comodo un metodo che accetti un “Anello” come parametro e che proceda a questa connessione; un metodo che ci consenta di scrivere qualcosa del tipo:<br />
<pre>int main()<br />
{<br />
Anello primo, secondo;<br />
<br />
primo.connetti(&secondo);<br />
}</pre><br />
Vediamo se riusciamo a mettere insieme questo metodo:<br />
<pre>void connetti(Anello* daCollegare)<br />
{<br />
// la proprietà 'successivo' deve puntare a daCollegare:<br />
successivo = daCollegare;<br />
}</pre><br />
Beh, non è stato così poi così difficile&nbsp;:-)<br />
<br />
La domanda potrebbe essere: «Già, ma come diciamo poi a ‘secondo’ che il suo predecessore è ‘primo’?»<br />
<br />
La prima soluzione che potrebbe venire in mente potrebbe essere di creare un metodo equivalente, ''sonoConnessoA()'', che imposti il ‘precedente’ per ogni “Anello”.<br />
<pre>void sonoConnessoA(Anello* daCollegare)<br />
{<br />
precedente = daCollegare;<br />
}</pre><br />
Questo ci porterebbe a dover aggiungere un altro rigo a main():<br />
<pre>int main()<br />
{<br />
Anello primo, secondo;<br />
<br />
primo.connetti(&secondo);<br />
secondo.sonoConnessoA(&primo);<br />
<br />
}</pre><br />
Vi sembra una buona soluzione?<br />
<br />
Vi rispondo io: funziona, ma obbliga a troppi passaggi, il ché significa che induce a commettere errori. Vediamo di fare meglio.<br />
<br />
Abbiamo già una funzione ''connetti()''. L’ideale sarebbe se questo metodo riuscisse a fare '''entrambe''' le cose, ossia connettere un “Anello” al successivo e poi istruire il successivo che il suo precedente è l’oggetto i cui metodi stiamo invocando in questo momento.<br />
<br />
Ma istruire l’oggetto successivo non è impossibile: infatti abbiamo un puntatore che lo tiene di mira (‘successivo’)!<br />
<br />
Quel che dobbiamo fare è raggiungere la proprietà ‘precedente’ dell’oggetto tenuto di mira e dirgli: «ehi! Il tuo ‘precedente’ sono io!».<br />
<br />
La prima parte è semplice, giacché<br />
<pre>successivo->precedente</pre><br />
ci consente di arrivare proprio lì, alla proprietà ‘precedente’ dell’oggetto tenuto di mira da ‘successivo’. Il problema è la seconda parte dell’istruzione.<br />
<pre>successivo->precedente =&nbsp;???&nbsp;;</pre><br />
‘precedente’ è un puntatore, perciò quello che ci serve è l’indirizzo di memoria dell’oggetto in cui siamo in questo momento…<br />
<br />
<br/>Già, è proprio così: anche questo dato ce l’abbiamo: è ''this''!<br />
<br />
Ecco la soluzione:<br />
<pre>#include <iostream><br />
<br />
class Anello {<br />
private:<br />
Anello* successivo;<br />
Anello* precedente;<br />
<br />
public:<br />
void connetti(Anello* daCollegare)<br />
{<br />
// la proprietà 'successivo' deve puntare a daCollegare:<br />
successivo = daCollegare;<br />
<br />
// la proprietà 'precedente' dell'Anello daCollegare<br />
// deve puntare a questo oggetto!<br />
successivo->precedente = this;<br />
}<br />
};<br />
<br />
int main()<br />
{<br />
Anello primo, secondo;<br />
<br />
primo.connetti(&secondo);<br />
}</pre><br />
L’istruzione #include &lt;iostream&gt; sarebbe inutile, ma tanta è l’abitudine…<br />
<br />
<br/>Questo è uno dei pochi casi in cui non si potrebbe ottenere il risultato senza ''this'', a meno che non si volesse scrivere un codice molto più complesso e ‘fragile’, nel senso di ‘con maggiori difetti’.<br />
<br />
<br/>Questo aspetto della maggiore o minore fragilità del codice risulterà più chiaro analizzando l’esempio originario di Stroustrup, il quale affronta anche i problemi collaterali (ossia: qual è il precedente del primo “Anello”? E il successivo dell’ultimo?).<br />
<br />
Lo riporto qui per intero, compresi i commenti originali dell’autore. Se però risultasse ostico, non vi preoccupate perché il testo di Stroustrup non è un aiuto per chi comincia da zero, come vuol essere questo, ma un punto di riferimento anche per chi è già un esperto.<br />
<br />
<br/>Codice dal libro ''The C++ Programming Language – Second Edition'' di Bjarne Stroustrup:&lt;/pre&gt;<br />
<br />
class dlink {<br />
<br />
dlink* pre; // previous<br />
dlink* suc; // next<br />
public:<br />
void append(dlink*);<br />
// ...<br />
};<br />
<br />
void dlink::append(dlink* p)<br />
{<br />
p->suc = suc; // that is p->suc = this->suc<br />
p->pre = this; // explicit use of "this"<br />
suc->pre = p; // that is, this->suc->pre = p<br />
suc = p; // that is, this-> suc = p<br />
}<br />
<br />
dlink* list_head;<br />
<br />
void f(dlink* a, dlink* b)<br />
{<br />
// ...<br />
list_head->append(a);<br />
list_head->append(b);<br />
}</pre><br />
<br />
Come vedete il prof. Stroustrup adotta una convenzione molto utile nello scrivere la class, ossia quella al rigo:<br />
<pre>void dlink::append(dlink* p)</pre><br />
Questo ci introduce direttamente all’argomento del prossimo capitolo, ma sul momento, per poter leggere il codice con il sistema che abbiamo usato fin qui, fate finta che sia stato scritto in questo modo:<br />
<pre>class dlink {<br />
dlink* pre; // previous<br />
dlink* suc; // next<br />
public:<br />
void append(dlink* p)<br />
{<br />
p->suc = suc; // that is p->suc = this->suc<br />
p->pre = this; // explicit use of "this"<br />
suc->pre = p; // that is, this->suc->pre = p<br />
suc = p; // that is, this-> suc = p<br />
}<br />
// ...<br />
};<br />
<br />
dlink* list_head;<br />
<br />
void f(dlink* a, dlink* b)<br />
{<br />
// ...<br />
list_head->append(a);<br />
list_head->append(b);<br />
}</pre><br />
Adesso che abbiamo un po’ cominciato a frequentare le class è arrivato il momento di scoprire perché abbiamo scritto tutto nel modo sbagliato&nbsp;:-)<br />
<br />
<br />
<br />
= Sorgenti e intestazioni: ogni cosa al suo posto =<br />
<br />
Questo mi auguro possa essere uno dei capitoli più rilassanti di questo tutorial. Non ci sono concetti da capire, infatti, ma solo un po’ di avvertenze per progettare in modo più ordinato.<br />
<br />
Proviamo un attimo a fare mente locale su ciò che abbiamo visto fin qui.<br />
<br />
<br/>Abbiamo scoperto che un programma in C++ è diviso in blocchi. Ci sono blocchi di diverso tipo, ma hanno in comune un grande vantaggio: ciò che succede al loro interno non influenza gli altri blocchi, se non per la parte che decidiamo noi tramite ''references'' e ''pointers''. All’esterno di questi blocchi si trovano solo le istruzioni per il compilatore (es. ''<nowiki>#include</nowiki>''), gli avvisi su ciò che si troverà in seguito (es. i ''namespace'' e i prototipi di funzione) e le dichiarazioni delle variabili globali.<br />
<br />
Queste variabili globali sono, si può dire, l’unica ‘falla’ alla sicurezza del codice, perché in un grande progetto in cui lavorano centinaia di persone diventa molto difficile prevedere come saranno usate. Per fortuna il C++ offre un semplice rimedio anche per questa falla. Vediamo come funziona.<br />
<br />
<br/>Quando siamo in tanti a lavorare sullo stesso progetto, ognuno lavora su un file diverso. È in fase di compilazione che i vari file vengono poi assemblati in un unico programma.<br />
<br />
Bene, il fatto è che anche ogni file rappresenta uno spazio di visibilità a sé stante. Ossia, non solo ogni funzione costituisce uno ''scope'' separato dagli altri con il beneficio che possiamo usare gli stessi nomi di variabile in funzioni diverse senza che questi interferiscano fra di loro, ma anche ogni file racchiude il suo ''scope'', cosicché possiamo impiegare gli stessi '''nomi di funzione''' in file diversi senza che questi influiscano gli uni sugli altri.<br />
<br />
E altrettanto si può dire delle variabili globali, giacché in realtà una variabile globale è globale… solo all’interno del file in cui è dichiarata! Per cui esiste un metodo che ci consente di precludere la visibilità delle variabili globali a certe parti del codice.<br />
<br />
Allo stesso tempo esiste un metodo simmetrico, che consiste nella parola magica ''extern'', che consente, da un file, di accedere a una variabile globale situata in un altro file. Se quindi sappiamo dell’esistenza di una variabile globale in un altro file e la vogliamo usare, possiamo farlo. Se non sappiamo della sua esistenza, possiamo scrivere tranquillamente il nostro codice senza paura di dare noia a nessuno.<br />
<br />
<br/>Tutte queste ‘misure di sicurezza’ dovrebbero consentire di farci dormire sonni tranquilli, ma non è detto che sia così perché un sistema troppo rigido renderebbe la programmazione un patimento, perciò si è cercato di rendere il meccanismo flessibile.<br />
<br />
Quanto abbiamo detto sopra '''non vale''' per esempio se usiamo il meccanismo ''<nowiki>#include</nowiki>''.<br />
<br />
Cosa significa la parola ''<nowiki>#include</nowiki>''? Si tratta di un’istruzione diretta al compilatore che fa in modo che quegli vada a prendere il file che gli indichiamo e lo copi '''per intero''' dentro il nostro. È ovvio che a quel punto, anche se noi li vediamo come file distinti, in realtà per il compilatore è come se fossero un unico file (o quasi: sto un po’ semplificando). A quel punto i nomi delle funzioni andranno in conflitto gli uni con gli altri.<br />
<br />
Non possiamo che ammettere che ''include'' conceda una grande flessibilità al codice – pensate per esempio alla comodità di scrivere un insieme di funzioni oggi e riciclarle fra dieci anni in un programma completamente diverso con la semplice scritta ''<nowiki>#include<miofile></nowiki>''. Ma, come tutte le medaglie, presenta il suo rovescio, che consiste nel fatto che si possono creare conflitti inattesi fra i nomi usati.<br />
<br />
<br/>Per fortuna sappiamo già come prevenire questi conflitti, ossia usando i ''namespace''. I ''manespace'' non sono una cosa che riguarda le classi, ma possono essere usati anche per racchiudere le funzioni. La mia funzione ''nomeACaso()'' racchiusa nel ''namespace'' ‘nmsp1’ potrà essere invocata con la scritta ''nmsp1:::nomeACaso()'', mentre la funzione ''nomeACAso()'' contenuta nel ''namespace'' ‘nmsp2’ sarà raggiungibile con ''nmsp2::nomeACaso()''.<br />
<br />
Non si deve però esagerare con l’uso dei ''namespace''. Teniamo di conto che l’intera libreria standard è racchiusa in un unico ''namespace'', ‘std’. Nella stragrande maggioranza dei casi, se possiamo rimediare al problema con il semplice cambio di qualche lettera nel nome della funzione, facciamolo e non pensiamoci più. Certi problemi si pongono solo quando si lavora in gruppi molto vasti e su programmi di notevoli dimensioni.<br />
<br />
<br/>Ma non esiste un modo migliore per gestire questo ‘attrito’ ''include/namespace''?<br />
<br />
In effetti esiste, e sono le ''class'' (nonché i ''template'', che sono un’evoluzione delle ''class'' e rappresentano lo strumento più potente, raffinato e flessibile del C++; ma ne parleremo… un bel dì).<br />
<br />
Se guardiamo il codice di una ''class'', ci troviamo dentro variabili (proprietà) e funzioni (metodi).<br />
<br />
Le proprietà sono visibili da tutti i metodi della classe, perciò assomigliano, nel loro piccolo, alle variabili globali. Diciamo che sono globali… all’interno della ''class''.<br />
<br />
Adesso facciamo un piccolo esercizio mentale: proviamo a visualizzare un programma composto in maniera ‘tradizionale’, ossia solo con variabili globali e funzioni, e, come se fosse scritto accanto, il codice di una ''class'' con le sue proprietà e metodi. Non vi sembra che si somiglino in modo impressionante?<br />
<br />
In effetti pare proprio che una ''class'' riproduca, in piccolo, un programma intero; è come se fosse un programma all’interno di un programma. Non sembra che sia come un programmino specializzato contenuto in un programma più grande?<br />
<br />
<br/>Guardandolo da questo punto di vista, ci vengono in mente due cose: la prima è che si potrebbe scrivere un intero programma in C++ usando solo le ''class''. L’unica funzione che sopravvivrebbe all’esterno di ogni ''class'' sarebbe ''main()'', che deve esiste perché rappresenta il punto di inizio dell’esecuzione.<br />
<br />
Scrivere un programma con questo metodo porterebbe solo vantaggi, perché i conflitti fra i nomi sarebbero pressoché eliminati, l’esigenza di ''references'' e ''pointers'' ridotta al minimo, la possibilità di migliorare il codice riscrivendo solo una parte senza causare danni a catena su tutto il resto portata al massimo. Si può dire che non esistano controindicazioni, o almeno io non ne vedo.<br />
<br />
E in effetti un sacco di programmi sono scritti così. Quando si parla di programmazione a oggetti s’intende in buona sostanza questo: concepire il codice come una serie di ''oggetti'' che interagiscono fra di loro. Se si riesce a concepire ''tutto'' il codice in questo modo, si ottengono grandi vantaggi da linguaggi come il C++.<br />
<br />
<br/>La seconda considerazione è che una piccola differenza la troviamo, fra un programma ‘tradizionale’ e una ''class'': i prototipi di funzione.<br />
<br />
In un programma tradizionale abbiamo bisogno di specificare al compilatore quali funzioni troverà, anticipandone il nome all’inizio del codice. In questa maniera possiamo aiutare il compilatore ad accorgersi di un sacco di errori. Invece nelle ''class'' che abbiamo scritto noi questa anticipazione sembra sia scomparsa: quando abbiamo scritto l’intestazione della funzione, immediatamente sotto c’era il suo ‘corpo’, ossia l’insieme delle istruzioni che la compongono.<br />
<br />
Il codice di Stroustrup che abbiamo visto sopra ci suggerisce però un’alternativa che ci consentirebbe di ripristinare l’equivalente dei prototipi di funzione all’interno delle ''class''.<br />
<br />
<br/>Per capire l’utilità di questo stile di scrittura possiamo fare un salto sul sito “cplusplus.com”<br />
<br />
([http://www.cplusplus.com/ http://www.cplusplus.com/]) e seguire il link Reference.<br />
<br />
<br/>[[File:Qt IV 19bis.png|Qt_IV_19bis.png]]<br />
<br />
<br/>Nella pagina che si apre, che presenta un lungo elenco dei file che compongono la libreria standard del C++, scegliamo, nel gruppo Containers, il link &lt;vector&gt;; poi ancora, sotto la scritta Classes, di nuovo vector. Scorriamo la pagina finché non troviamo la scritta Member types e lì sotto selezioniamo la scheda C++11 (ormai dovremmo sapere a cosa si riferisce!).<br />
<br />
<br/>[[File:Qt IV 20.png|Qt_IV_20.png]]<br />
<br />
<br/>Questo sito è una delle migliori risorsi esistenti su Internet per chi vuole imparare il C++. Se scorriamo questa pagina, quella che troviamo è una sintetica ma precisa descrizione di cos’è un ''vector'' nel C++; in particolare, sotto il titolo Member functions compare un elenco dei suoi metodi pubblici.<br />
<br />
È meglio precisare subito che un ''vector'' non è una ''class'', bensì un ''template'', cioè una specie di ''class'' resa ancora più flessibile e produttiva; abbiamo visto infatti che un ''vector'' può contenere qualsiasi tipo di dato, dai comuni interi (''vector&lt;int&gt;'') al testo (''vector&lt;sting&gt;'') a oggetti creati dall’utente (''vector&lt;Robot&gt;''). Questa è una caratteristica dei ''template'', ma per tante altre cose sono identici alle ''class'', per cui ora come ora consideriamolo una ''class'' senza complicarci troppo la vita. Esattamente come le ''class'', i ''template'' hanno proprietà e metodi, che possono essere sia privati che pubblici.<br />
<br />
<br/>Guardate un po’ com’è lungo l’elenco dei metodi pubblici: (constructor), (destructor), operator=, begin(), end(), rbegin(), rend(), cbegin(), cend(), crbegin(), crend(), size(), max_size(), resize(), capacity(), empty(), reserve(), shrink_to_fit(), operator[], at(), front(), back(), data(), assign(), push_back(), pop_back(), insert(), erase(), swap(), clear(), emplace(), emplace_back(), get_allocator.<br />
<br />
Lasciamo stare che alcuni nomi, come ''operator[]'', ci possano risultare misteriosi; cerchiamo invece di raffigurarci come sarebbe cercare il capire il funzionamento di una classe dovendo leggere tutte le centinaia di righe di codice di cui è composto. Il fatto è che, per usare un ''vector'', tutte queste informazioni '''non''' sono necessarie: a noi basta sapere '''cosa''' fa, senza stare a porci la domanda di '''come''' lo fa.<br />
<br />
<br/>Mettiamo il caso che il programmatore abbia, con pregevole cortesia, scritto delle righe di presentazione all’inizio di ogni metodo; in tal caso a noi basterebbe leggere quelle, ignorando tutto il resto.<br />
<br />
Come potete immaginare, non siamo i primi a cui è venuta in mente questa considerazione: il C++ offre il supporto utile a comporre le ''class'' in una maniera molto ordinata e pulita, in modo tale che, dopo averle lasciate in un cassetto per anni e anni, siamo in grado di riprenderle in mano ricostruendo in poco tempo a cosa servivano e come si usavano.<br />
<br />
La logica del metodo è questa: il ''corpo'' dei metodi rappresenta il come, non il cosa, quindi non ci interessa leggerlo. Invece l’elenco delle proprietà e la '''descrizione''' dei metodi è ciò che ci consente di capire cosa fa una ''class'', perciò vogliamo trovarlo ben ordinato senza tante righe inutili in mezzo.<br />
<br />
Meglio ancora: la '''descrizione''' delle proprietà e dei metodi di una ''class'' dovrebbe trovarsi da sola su un file a parte, mentre i ''corpi'' dei metodi –in pratica i blocchi di codice fra le parentesi graffe– starebbero bene su un altro file, dove non danno noia.<br />
<br />
<br/>Ciò può essere ottenuto con la tecnica di prototipi di funzione: in pratica in un file elenchiamo le proprietà e i prototipi dei metodi, e in un altro i corpi dei metodi.<br />
<br />
<br/>Vediamo questa idea in pratica con la ''class'' Robot.<br />
<br />
Il codice che a noi interessa è questo:<br />
<pre>class Robot{<br />
string nome;<br />
int carica;<br />
int x;<br />
int y;<br />
<br />
public:<br />
Robot(string pa_nome);<br />
void setNome(string battezza);<br />
string getNome()<br />
void vaiSu();<br />
void vaiGiu();<br />
void vaiSx();<br />
void vaiDx();<br />
void datiASchermo();<br />
~Robot();<br />
};</pre><br />
Invece quello che non ci interessa leggere è questo:<br />
<pre>Robot(string pa_nome)<br />
{<br />
nome = pa_nome;<br />
x = 0;<br />
y = 0;<br />
carica = 100;<br />
}<br />
<br />
void setNome(string battezza)<br />
{<br />
nome = battezza;<br />
}<br />
<br />
string getNome()<br />
{<br />
return nome;<br />
}<br />
<br />
void vaiSu()<br />
{<br />
y += 1;<br />
carica -= 5;<br />
}<br />
<br />
void vaiGiu()<br />
{<br />
y -= 1;<br />
carica -= 5;<br />
}<br />
<br />
void vaiSx()<br />
{<br />
x -= 1;<br />
carica -= 5;<br />
}<br />
<br />
void vaiDx()<br />
{<br />
x += 1;<br />
carica -= 5;<br />
}<br />
<br />
void datiASchermo()<br />
{<br />
cout << "Robottino '" << nome << "':" << endl;<br />
cout << " posizione: x = " << x << ", y = " << y << endl;<br />
cout << " carica residua: " << carica << "%" << endl;<br />
cout << endl << endl;<br />
}<br />
<br />
~Robot()<br />
{<br />
cout << endl << endl;<br />
cout << "Torna presto a trovarci!" << endl << endl;<br />
}</pre><br />
In base a ciò che abbiamo detto, quello che vorremmo è prendere quest’ultimo pezzo di codice e spostarlo su un altro file. Arrivato il momento della compilazione, diremo a Qt che quel file fa parte del nostro progetto e lui provvederà a ‘riattaccarlo’ insieme agli altri nel nostro programma.<br />
<br />
Però ci viene subito un dubbio: come può fare il compilatore a sapere che le funzioni che trova qui sono i metodi della ''class'' “Robot”? Visto che i nomi dichiarati in una ''class'' sono invisibili all’esterno, il compilatore non ha modo di decidere se questi sono i corpi dei metodi dichiarati da noi oppure ‘normali’ funzioni scritte da qualcun altro che nulla sa della nostra ''class''. Certo sarebbe una bella coincidenza, questo è vero, ma ciò nonostante non possiamo lasciare al compilatore la responsabilità di decidere.<br />
<br />
<br/>Chi ha studiato con cura il codice che abbiamo ripreso da Stroustrup avrà già trovato la soluzione, che consiste nell’utilizzo del simbolo ‘::’, che, non a caso, è detto operatore di ''scope resolution''.<br />
<br />
Quel che dobbiamo fare è preporre al nome della funzione il nome della ''class'' di cui è metodo, ponendo fra i due il simbolo ‘::’. In pratica: ''Robot::datiASchermo()''.<br />
<br />
In questo modo il compilatore sa che questi sono i corpi di metodi i cui prototipi sono dichiarati in un altro file, dove c’è la parte ‘utile da leggere’ della ''class''.<br />
<br />
I nomi delle nostre funzioni diventeranno quindi:<br />
<pre>Robot::Robot(string pa_nome)<br />
{<br />
…<br />
}<br />
<br />
void Robot::setNome(string battezza)<br />
{<br />
…<br />
}<br />
<br />
string Robot::getNome()<br />
{<br />
…<br />
}<br />
<br />
void Robot::vaiSu()<br />
{<br />
…<br />
}<br />
<br />
void Robot::vaiGiu()<br />
{<br />
…<br />
}<br />
<br />
void Robot::vaiSx()<br />
{<br />
…<br />
}<br />
<br />
void Robot::vaiDx()<br />
{<br />
…<br />
}<br />
<br />
void Robot::datiASchermo()<br />
{<br />
…<br />
}<br />
<br />
~Robot()<br />
{<br />
…<br />
}</pre><br />
Come dicevo, in questo capitolo non sono spiegati concetti nuovi, però non bisogna sottovalutare l’importanza di questo passaggio: le class nel C++ si scrivono con questa tecnica e qualsiasi IDE scegliessimo di usare si aspetterebbe che le volessimo così.<br />
<br />
Il C++ è, in generale, considerato un linguaggio un po’ complicato, perciò non dovremmo mai pensare che l’ordine e la leggibilità del codice siano aspetti marginali.<br />
<br />
<br/>Scrivere un ''class'' ha quindi una difficoltà iniziale, che è decidere a '''cosa''' serve, ossia a che fine la progettiamo. Questa è la parte più astratta, ma anche più fascinosa della programmazione a oggetti.<br />
<br />
Dopo si incorre in una serie di difficoltà pratiche che consistono nel trovare le soluzioni alle varie problematiche che si presentano via via che si scrive il codice.<br />
<br />
Oltre a tutto ciò, che anche una necessità di metodo e ordine che, almeno per me, rappresenta la parte più noiosa.<br />
<br />
A voler essere completi, aggiungerei che tutto ciò che scriviamo dovrebbe essere documentato, ossia accompagnato da numerose righe di commento che ci rendano più semplice ricordarci cosa avevamo in mente quando l’abbiamo scritto.<br />
<br />
<br/>Non credo sia un caso se tutti gli IDE si offrono di darci una mano sotto l’aspetto dell’ordine. Può darsi che non sia il solo a trovarlo un passaggio un po’ ripetitivo. Anche Qt avrebbe voluto semplificarci un po’ la vita, se non avessimo respinto il suo aiuto. È arrivato però il momento di scoprire come fare in modo che, al momento della progettazione di una ''class'', Creator si occupi al posto nostro di:<br />
<br />
*aggiungere due file al nostro progetto;<br />
*predisporre uno dei due perché contenga la parte leggibile di una class;<br />
*predisporre l’altro perché ospiti i corpi dei metodi.<br />
<br />
Per scoprire queste funzioni, chiudiamo il progetto aperto e tutti i relativi files e creiamo un Robot2, che finirà per essere identico a Robot se non per il fatto che il codice sarà, una buona volta, in ordine.<br />
<br />
<br/>Inserisco le immagini delle operazioni, ma, se la vostra versione di Qt è in lingua italiana, non saranno identiche.<br />
<br />
Le prime dovrebbero essere assai familiari: nuovo progetto<br />
<br />
<br/>[[File:Qt IV 21bis.png|Qt_IV_21bis.png]]<br />
<br />
<br/>Scegliere un progetto '''senza''' le librerie Qt (Non-Qt Project) e, nella colonna centrale, un progetto C++ vuoto (Plain C++ Project).<br />
<br />
<br/>[[File:Qt IV 22.png|Qt_IV_22.png]]<br />
<br />
<br/>Selezionare la cartella e scegliere un nome coerente – io scrivo Robot2:<br />
<br />
<br/>[[File:Qt IV 23.png|Qt_IV_23.png]]<br />
<br />
<br />
<br />
Nelle schermate successive lasciare tutto com’è.<br />
<br />
Quando ci si trova davanti il nostro nuovo progetto ‘pulito’, eccetto per il codice ‘Hello Word’, chiedere a Creator di aggiungere una nuova ''class'' al progetto. Per far ciò, selezionare File → Nuovo file o progetto (New File or Project):<br />
<br />
<br/>[[File:Qt IV 24bis.png|Qt_IV_24bis.png]]<br />
<br />
<br/>Nella schermata che segue selezionare C++ Files and Classes: C++ → C++ Class. Infine confermare.<br />
<br />
<br/>[[File:Qt IV 25bis.png|Qt_IV_25bis.png]]<br />
<br />
<br/>Se però si presta attenzione a cosa compare scritto nella colonna di destra, si avranno informazioni su ciò che sta per succedere. Infatti Creator ci comunica che, in base alla nostra scelta, verranno creati due file, uno ''header'' e un ''source''. È ciò che desideriamo noi perché un ''header'' è un tipo di file di testo, con estensione di solito .h, che è idoneo a contenere la parte utile da leggere di una ''class''<nowiki>; </nowiki>un ''source'' un file, nel C++ spesso con estensione .cpp, dove ci si può aspettare di trovare i corpi dei metodi.<br />
<br />
Andiamo avanti.<br />
<br />
<br/>Nella schermata successiva, specificate, come nome della ''class'', Robot. Potete scrivere Robot indipendentemente da come avete chiamato il progetto, giacché possiamo creare una ''class'' Robot in qualsiasi programma non ce ne sia già una – o meglio, non ce ne sia già una che non sia nascosta in un ''namespace''.<br />
<br />
Lasciate tutto il resto com’è.<br />
<br />
Creator vi sta già segnalando come intende chiamare i due file: lo ''header'' “robot.h” e il ''source'' “robot.cpp”. Potremmo scegliere qui altri nomi, ma chi ce lo fa fare?<br />
<br />
<br/>[[File:Qt IV 26.png|Qt_IV_26.png]]<br />
<br />
<br/>Andiamo alla schermata successiva.<br />
<br />
Questo è soltanto un riepilogo. Potete studiarlo per confermarvi di aver capito cosa sta per succedere, poi dare il vostro assenso.<br />
<br />
<br/>[[File:Qt IV 27.png|Qt_IV_27.png]]<br />
<br />
<br/>Ecco che siamo tornati al nostro progetto.<br />
<br />
Però, se guardate bene, non è più come prima: nella colonna centrale compare una nuova scritta: “Headers”. Se fate click sulla freccetta nera sulla sinistra, si apre e lascia apparire il nostro primo ''header file'': “robot.h”.<br />
<br />
Più in basso, nella stessa ‘categoria’ di “main.cpp” (che ora scopriamo essere un ''source file'') troviamo il corrispondente “robot.cpp”.<br />
<br />
<br/>[[File:Qt IV 28bis.png|Qt_IV_28bis.png]]<br />
<br />
<br/>A parte ricordarsi i menu da scegliere, mi sembra che da un punto di vista concettuale ancora non abbiamo detto niente di difficile.<br />
<br />
Adesso, visto che il numero dei file del nostro progetto per la prima volta è superiore a uno, conviene capire come si fa a spostarsi dall’uno all’altro.<br />
<br />
<br/>L'impostazione di Creator, che io trovo molto comoda, ma non è detto piaccia a tutti, è di riempire sempre la colonna di destra con il file che si è selezionato. In altre parole, se in questo momento abbiamo scelto “robot.cpp”, il codice che vediamo a destra è il contenuto del file “robot.cpp”.<br />
<br />
Per spostarsi in un altro file ci sono due metodi: il più naturale consiste nel fare doppio click sul nome del file nella colonna centrale che si vuole visualizzare.<br />
<br />
Proviamo ad esempio a entrare in “robot.h” con questo sistema:<br />
<br />
<br/>[[File:Qt IV 29bis.png|Qt_IV_29bis.png]]<br />
<br />
<br/>L’altro sistema, che pare meno spontaneo, finisce per essere il preferito dopo un po’ di tempo che si usa Creator. Se guardate sopra la colonna di destra, trovate una barra grigio scuro con una serie di simboli. In uno di quelli è riportato il nome del file visualizzato, “robot.h”.<br />
<br />
Se facciamo click sulla doppia freccia verticale che c’è alla destra di questo nome, si apre un comodo menù tramite il quale possiamo passare rapidamente da un file all’altro:<br />
<br />
<br/>[[File:Qt IV 30bis.png|Qt_IV_30bis.png]]<br />
<br />
<br/>Adesso diamo una breve occhiata al codice che Qt ha pensato bene di inserire senza che noi glielo chiedessimo.<br />
<br />
Possiamo partire dal presupposto che, se l’ha fatto, ci deve essere un motivo. Il motivo, però, ora sarebbe un gran noia tecnica da spiegare, anche se non c’è niente di difficile. Visto che questa parte del tutorial sta diventando lunghissima, diciamo che ce lo lasciamo in caldo per un’altra puntata. A noi può bastare sapere che quelle righe che iniziano con ‘#’ sono istruzioni per il compilatore ed è meglio se le sciamo dove stanno. Un giorno, però, impareremo a metterci le mani.<br />
<br />
<br/>La parte centrale del file è invece un comodo aiuto che Creator ci offre per farci scrivere meno codice: visto che l’abbiamo informato che volevamo scrivere una ''class'' di nome “Robot”, ha già iniziato a farlo lui per noi.<br />
<br />
Ecco lì il blocco iniziale, con il suo punto e virgola finale, la scritta ''public'' perché tanto c’è pressoché sempre, nonché la dichiarazione del costruttore. Avevamo detto o no che conveniva specificarlo sempre? Beh, ci ha già pensato Creator.<br />
<br />
<br/>Adesso facciamo una scappata in “robot.cpp” e troviamo un passaggio molto importante:<br />
<pre>#include "robot.h"</pre><br />
Vi sembra strano?<br />
<br />
Dovrebbe essere ovvio: “robot.cpp” e “robot.h” sono due componenti dello stesso oggetto, la class “Robot”. Non possono vivere due vite separate. Il Compilatore deve sapere dove andare a trovare i prototipi delle funzioni che incontra qui, e quelli sono contenuti in “robot.h”. O, per meglio dire: ancora non ci sono contenuti, ma ce li stiamo per inserire noi!<br />
<br />
Forza, al lavoro, pigroni!<br />
<br />
Il prossimo esercizio è questo: copiate il contenuto del progetto “robottino” in “Robot2”, stando ben attenti a inserire le cose giuste al posto giusto. Alla fine dei giochi, il programma deve compilare e eseguire correttamente.<br />
<br />
Attenzione! Vi dovrebbero rimanere solo due funzioni esterne alla classe, e una delle due è ''main()''.<br />
<br />
Altra cosa: ricordatevi che in “robot.cpp” è dovuta comparire un’istruzione ''<nowiki>#include</nowiki>''… Nel file “main.cpp” cosa dovrà essere aggiunto?<br />
<br />
<br/>Se pensate che vi dia la soluzione qui, vi sbagliate&nbsp;:-O<br />
<br />
Si tratta solo di copiare e ragionare un po’, suvvia! E poi non abbiamo tempo, perché ci aspetta qualcosa di ''new''.<br />
<br />
<br />
<br />
= Qualcosa non poi così new =<br />
<br />
PREMESSA. Per i prossimi esempi sono tornato a sfruttare il progetto “Prove”, che abbiamo detto ci sarebbe servito per scrivere codice misto.<br />
<br />
Come al solito chi non vuole perdere il vecchio codice può o salvarlo o creare un nuovo progetto, sempre di tipo non-Qt.<br />
<br />
<br />
<br />
== I nei dei puntatori ==<br />
<br />
Vi ricordate cosa commentavamo all’inizio di questo quarto tutorial?<br />
<br />
Si diceva che un linguaggio che ammettesse solo variabili globali e locali senza prevedere altre soluzioni sarebbe un po’ rigido. Poi abbiamo scoperto che le ''class'' ci consentivano soluzione intermedie.<br />
<br />
<br/>Adesso pensiamo un po’ ai puntatori e chiediamoci se non ci siano degli aspetti nei quali li miglioreremmo.<br />
<br />
Abbiamo visto per esempio che un puntatore può essere dichiarato senza avere nulla da puntare, ma in quel caso è di ben scarsa utilità.<br />
<br />
Oltre a ciò, i puntatori che abbiamo visto fin qui paiono davvero un po’ scomodi: infatti bisogna prima creare un ‘qualcosa’ in memoria, tipo una variabile intera o una variabile oggetto, e solo dopo che essa esiste allora si può passare il suo indirizzo al puntatore. Pare quindi che, per poter usare un puntatore, si debba comunque già avere una variabile. Il puntatore, a queste condizioni, appare una sorta di duplicato, una specie di passaggio intermedio obbligato per poter far modificare una variabile a un’altra funzione.<br />
<br />
<br/>Continuando a ragionarci su, ci vengono altri dubbi sull’utilità dei ''pointers''. Vi siete chiesti che cosa succede al valore di ritorno di una funzione se quel valore è un puntatore? In questo caso la restituzione di valori al chiamante procederà senza errori? Mi spiego con un esempio.<br />
<br />
Mettiamo di avere una funzione che riceve restituisce un ''pointer'' a ''int'' Un esempio potrebbe essere:<br />
<pre>int* restUnInt()<br />
{<br />
int numInt = 47; // Un numero a caso<br />
int* daRestituire = &numInt;<br />
<br />
return daRestituire;<br />
}</pre><br />
La funzione chiamante, che può essere anche main(), deve soltanto creare un puntatore che riceva il valore di ritorno di restUnInt():<br />
<pre>int main()<br />
{<br />
int* valRitorno;<br />
<br />
valRitorno = restUnInt();<br />
cout << "valRitorno = " << *valRitorno << endl << endl;<br />
}</pre><br />
Secondo voi questo programma funzionerà? Ci trovate qualche difetto?<br />
<br />
Quale sarà l’output?<br />
<br />
Chi scommette su “valRitorno = 47”?<br />
<br />
<br/>Mentre ci pensate, riporto il codice completo a uso e consumo dei (soliti) pigroni:<br />
<pre>#include <iostream><br />
<br />
using std::cout;<br />
using std::endl;<br />
<br />
int* restUnInt();<br />
<br />
int main()<br />
{<br />
int* valRitorno;<br />
<br />
valRitorno = restUnInt();<br />
cout << "valRitorno = " << *valRitorno << endl << endl;<br />
}<br />
<br />
int* restUnInt()<br />
{<br />
int numInt = 47; // Un numero a caso<br />
int* daRestituire = &numInt;<br />
<br />
return daRestituire;<br />
}</pre><br />
Vediamo come è andata la scommessa. Il mio risultato è il seguente:<br />
<br />
<br/>[[File:Qt IV 31.png|Qt_IV_31.png]]<br />
<br />
<br/>Parrebbe quindi che chi ha scommesso sul 47 abbia vinto. Ma la vittoria sarebbe valida lo stesso se fosse dovuta a un puro caso?<br />
<br />
Vi suona strano che l’output di un programma possa dipendere dal caso?<br />
<br />
Ebbene, forse vi sorprenderà sapere che il fatto che a me, sul mio computer, il programma abbia restituito 47 non implica che a qualcun altro non abbia dato un risultato completamente diverso. Le variabili in gioco sono tante e la prima è di quanta memoria dispone il vostro computer.<br />
<br />
<br/>Ciò di cui stiamo parlando in realtà è la naturale conseguenza di cose già viste, ma cercheremo lo stesso di entrare nell’argomento passo passo.<br />
<br />
Alle persone cui il programma ha risposto 47 sarà rimasta l’impressione che non ci sia niente di strano. La variabile ‘numInt’ è stata inizializzata con il valore 47; il puntatore ‘daRestituire’ ha ricevuto l’indirizzo di ‘numInt’, perciò ha iniziato a tenere di mira un’area di memoria dove era contenuto il valore 47.<br />
<br />
Infine copia di questo indirizzo è stata passata a ‘valRitorno’, perciò anche questo puntatore ha iniziato a tenere di mira un’area di memoria dov’era contenuto il valore 47…<br />
<br />
<br/>Mmmh! Ne siete proprio sicuri?<br />
<br />
Lasciate che vi faccia una domanda. Se così fosse, allora il puntatore continuerebbe a puntare a un’area di memoria dov’è contenuto il valore 47 anche in seguito. Ossia, se io ''dereferenziassi'' il puntatore dopo qualche riga di codice, dovrei avere sempre la stessa risposta. Sempre 47. Giusto?<br />
<br />
<br/>Ebbene proviamo:<br />
<pre>#include <iostream><br />
<br />
using std::cout;<br />
using std::endl;<br />
<br />
int* restUnInt();<br />
void qualcheOperazione();<br />
<br />
int main()<br />
{<br />
int* valRitorno;<br />
<br />
valRitorno = restUnInt();<br />
cout << "valRitorno = " << *valRitorno << endl;<br />
<br />
qualcheOperazione();<br />
<br />
cout << "valRitorno = " << *valRitorno << endl << endl;<br />
}<br />
<br />
int* restUnInt()<br />
{<br />
int numInt = 47; // Un numero a caso<br />
int* daRestituire = &numInt;<br />
<br />
return daRestituire;<br />
}<br />
<br />
void qualcheOperazione()<br />
{<br />
int i1 = 7; // un numero a caso<br />
int i2 = 19; // un numero a caso<br />
<br />
cout << "7 x 19 = " << i1 * i2 << endl;<br />
}</pre><br />
Ho apportato delle modifiche minime al codice e nessuna di queste tocca il puntatore ‘valRitorno’.<br />
<br />
Anzi, per essere sicuro di non interferire, ho spostato le operazioni in un’altra funzione, ''qualcheOperazione()'', che non accetta parametri e non restituisce nulla. Potete verificare con i vostri occhi: ‘valRitorno’ è rimasto inalterato. Punta quindi sempre alla stessa cella di memoria.<br />
<br />
E il risultato che ottengo è questo:<br />
<br />
<br/>[[File:Qt IV 32.png|Qt_IV_32.png]]<br />
<br />
<br/>La cosa più strana è che a qualcuno ‘valRitorno’ potrebbe continuare a restituire 47, mentre ad altri potrebbe non farlo già la prima volta.<br />
<br />
<br/>Ma c’è davvero qualcosa di strano?<br />
<br />
Ripensiamo a ciò che abbiamo detto a proposito delle funzioni. Quando una funzione termina, il suo spazio di memoria viene cancellato e riutilizzato per altre funzioni o altri programmi. La variabile ‘numInt’, il cui indirizzo stiamo tenendo di mira, per l’appunto era una variabile locale a una funzione, ''restUnInt()''. Quando ''restUnInt()'' è terminata, tutta la memoria che occupava è stata dichiarata libera e disponibile. Da quel momento, non c’era più nessuna garanzia di quale fosse diventato il valore dell’area di memoria con etichetta ‘numInt’.<br />
<br />
<br/>Ovviamente non è possibile prevedere quando il computer riuserà esattamente '''quella''' memoria. Sul mio pc è successo che, in un primo momento, non ne avesse bisogno, perciò l’ha lasciata stare. Avendola lasciata stare, quando ho dereferenziato ‘valRitorno’ la prima volta il valore che era presente nella cella di memoria che era stata etichettata ‘numInt’ era ancora 47.<br />
<br />
Nel momento in cui però l’esecuzione del programma ha chiesto al computer un po’ di memoria per eseguire una nuova funzione, ''qualcheOperazione()'', questi ha messo a disposizione quella che prima era la memoria di ''restUnInt()''. A quel punto il valore di quella cella di memoria è stato modificato in una maniera imprevedibile.<br />
<br />
Fatto sta che ‘valRitorno’ ha continuato a puntare lì, perché era quello che gli avevamo ordinato di fare.<br />
<br />
<br/>Il mio economico portatile con 4Gb di RAM ha dovuto riciclare la stessa memoria abbastanza in fretta, ma se avete un buon pc con 16Gb può darsi che il sistema operativo non la tocchi per alcuni secondi. Detto nella maniera più semplice possibile: è imprevedibile. Il risultato cambierà a ogni esecuzione in base a quali programmi sono attivi e a mille altri fattori su cui non possiamo fare niente.<br />
<br />
<br/>A questo punto sembrerebbe che avessimo trovato un nuovo difetto ai nostri amici puntatori: a una prima vista parrebbero poco idonei per costituire valori di ritorno per le funzioni.<br />
<br />
Questa è però più un’apparenza che una sostanza perché sono usatissimi anche a tale scopo, solo con alcuni accorgimenti.<br />
<br />
Tanto per citarne uno, se passate un puntatore a una funzione, vuol dire che state passando a quella funzione l’indirizzo di un’area di memoria che si trova al di fuori della funzione stessa. La conclusione è che quell’aria di memoria '''non''' sarà distrutta al termine della funzione. È quindi possibile restituire con sicurezza un nuovo puntatore a quell’area, se la cosa può essere utile.<br />
<br />
<br />
<br />
== Una memoria indistruttibile ==<br />
<br />
Scava scava, siamo riusciti a trovare degli aspetti in cui anche i puntatori sembrano deluderci un po’. In realtà, più che veri e propri difetti bisognerebbe parlare di una filosofia sottostante al linguaggio C++.<br />
<br />
<br/>Una caratteristica del C++ che alcuni considerano senza mezzi termini un difetto è il fatto che non offre molte tutele al programmatore. In buona sostanza, al compilatore non è richiesto di metterci in guardia se facciamo una cosa poco sicura come chiedere di accedere a un’area di memoria che non sappiamo dove si trovi né cosa ci sia dentro. L’avevamo già visto nel tutorial precedente, solo che in quel caso il compilatore almeno un avviso era riuscito a darcelo; adesso non otteniamo nemmeno quello.<br />
<br />
Per chi è abituato a altri linguaggi questo comportamento è censurabile perché, secondo alcuni, le cose poco sensate andrebbero proibite; sul lato opposto ci sono programmatori appassionati di C++ che si fanno quasi un vanto del fatto che per padroneggiare questo linguaggio servano tempo e fatica.<br />
<br />
<br/>Come al solito mi permetto un commento laico: il C++ è un linguaggio come tanti; ad alcuni piacerà, ad altri no. Ci sono dei linguaggi che cercano di aiutare il programmatore a non sbagliare; la politica del C++ è invece: tutto ciò che non è esplicitamente proibito, è concesso. Che poi funzioni, è un altro paio di maniche&nbsp;:-)<br />
<br />
Secondo me la discussione si risolve ammettendo che nel C++ si deve procedere passo passo, senza fretta, cercando di sviscerare i pro e i contro delle soluzioni che offre.<br />
<br />
<br/>In questa situazione, per esempio, alle caratteristiche dei puntatori che non ci piacciono offre una soluzione, che è la parola magica ''new''. Anche di questa bisognerà capire vantaggi e svantaggi.<br />
<br />
<br/>Cominciamo da una domanda dall’apparenza un po’ superficiale: ma perché insisto a chiamarla parola magica? Non potrei chiamarla istruzione, come ho fatto per ''for'', ''while'', ''if''…?<br />
<br />
Beh, in fondo non verrebbe nessuno a bastonarmi –o almeno spero–, ma rimane il fatto che ''new'' di per sé nel C++ è definita come un ''operator'', un operatore. Rientra cioè nel gruppo dei simboli come ‘==’, ‘[]’, ‘{}’, ‘::’, ‘*’, eccetera. La differenza è che è composta di lettere e non di asterischi o parentesi o due punti, ma la cosa non deve portarci fuori strada.<br />
<br />
<br/>Dovete sapere che nei corsi seri sul C++ c’è sempre un punto in cui vengono presentate lunghe tabelle con l’elenco dei simboli e di quello che si chiama ‘ordine di precedenza’ o di ‘valutazione’. Non voglio negare la loro importanza, ma ribadisco che qui vogliamo fare una carrellata generale, cercando di rompere il ghiaccio con il linguaggio, e non di sviscerarlo in maniera scientifica. Perciò rimanderemo anche questo noiosiss… ehm, importantissimo argomento.<br />
<br />
<br/>Cosa fa dunque ''new''?<br />
<br />
Lo si può dire in due parole: ''new'' è capace di costruire un’istanza dell’oggetto che desideriamo direttamente in memoria e di restituire un puntatore a quell’oggetto.<br />
<br />
<br/>Se non è chiaro, due righe di codice renderanno tutto comprensibile.<br />
<br />
Per creare un oggetto fin’ora avevamo un unica possibilità: definire un variabile che fungesse da ‘etichetta’ di quell’oggetto:<br />
<pre>Robot istanzaDiRobot;</pre><br />
A questo punto ci trovavamo con un oggetto, come dire, ‘reale’, che occupava un’area di memoria.<br />
<br />
Se invece dichiaravamo un puntatore allo stesso tipo di oggetto:<br />
<pre>Robot* puntAOggettoRobot;</pre><br />
ci trovavamo con un puntatore, ma non con un oggetto, nel senso che nessuna istanza di class andava a occupare alcuno spazio di memoria.<br />
<br />
<br/>Se infine volevamo un puntatore che davvero puntasse a un oggetto esistente, non avevamo altra scelta che creare un’istanza di ''class'' e poi passare il suo indirizzo al puntatore:<br />
<pre>puntAOggettoRobot = &istanzaDiRobot;</pre><br />
Riassumendo, le istruzioni erano come minimo due:<br />
<pre>Robot istanzaDiRobot; // creo l’oggetto in memoria<br />
Robot* puntAOggettoRobot = &istanzaDiRobot; // ottengo un pointer all’oggetto</pre><br />
Un po’ una perdita di tempo, forse.<br />
<br />
''new'' consente di riassumere queste due istruzioni in una sola:<br />
<pre>Robot* puntAOggettoRobot = new Robot;</pre><br />
Il risultato di questa istruzione è che viene creato un’istanza della class “Robot”, ma non le viene data alcuna etichetta; però viene inserito il suo indirizzo di memoria nel puntatore ‘puntAOggettoRobot’.<br />
<br />
Da questo momento sarà possibile accedere all’oggetto creato tramite il puntatore, anche se non ha un ‘nome’.<br />
<br />
<br/>Il vantaggio incredibile di creare un oggetto con l’istruzione<br />
<pre>Robot* puntAOggettoRobot = new Robot;</pre><br />
anziché con<br />
<pre>Robot istanzaDiRobot;</pre><br />
è che, trovandoci in mano un puntatore, possiamo passarlo senza problemi come parametro alle varie funzioni, rendendolo di fatto modificabile da ogni punto del programma, ma senza bisogno di dichiararlo globale.<br />
<br />
In altre parole, abbiamo un oggetto che '''non''' è globale, ma con semplici accorgimenti può comportarsi come se lo fosse.<br />
<br />
Pensate un po’ alla differenza: una variabile globale può essere modificata per errore da qualcuno che non sa della sua esistenza; al contrario, un oggetto non globale può essere modificato '''solo''' da chi sa della sua esistenza. Inoltre, a meno che un programmatore non sia così sempliciotto da non tener di conto dei nomi degli argomenti della funzione su cui sta lavorando, è pressoché impossibile che il nome del puntatore sia mascherato per errore.<br />
<br />
<br/>Quindi ''new'' sembrerebbe un buon rimedio al primo ‘neo’ dei puntatori: il fatto che, per essere davvero utili, ci obbligano a trovar loro un oggetto già esistente in memoria da tener di mira.<br />
<br />
Ma sarà in grado di aiutarci anche nella seconda, ossia che i puntatori non sembrano essere la scelta migliore per far restituire valori alle funzioni?<br />
<br />
<br/>Per rispondere al quesito è necessario dare un’occhiata a ''come fa'' a fare ciò che fa; solo dopo potremo valutare pro e contro.<br />
<br />
<br/>Cercate di prevedere quale potrebbe essere lo output del seguente codice prima di andare a guardarlo:<br />
<pre>#include <iostream><br />
<br />
using std::cout;<br />
using std::endl;<br />
<br />
class Qualsiasi{}; // la class è vuota, ma si puo' usare lo stesso<br />
<br />
void indagineSuNew();<br />
<br />
Qualsiasi globalQual; // istanza della classe Qualsiasi<br />
// con visibilità globale<br />
<br />
int main()<br />
{<br />
Qualsiasi mqual; // nome a caso<br />
Qualsiasi* p_mqual = &mqual;<br />
Qualsiasi* p2_mqual = new Qualsiasi;<br />
<br />
cout << "Indirizzo di globalQual = "<br />
<< (unsigned long) &globalQual << endl;<br />
<br />
cout << "Indirizzo di mqual = " << (unsigned long) p_mqual << endl;<br />
cout << "Indirizzo di p_mqual = " << (unsigned long) &p_mqual << endl;<br />
cout << "Indirizzo di p2_mqual = "<br />
<< (unsigned long) p2_mqual << endl;<br />
indagineSuNew();<br />
}<br />
<br />
void indagineSuNew()<br />
{<br />
Qualsiasi fqual; // nome a caso<br />
Qualsiasi* p_fqual = &fqual;<br />
Qualsiasi* p2_fqual = new Qualsiasi;<br />
<br />
cout << "Indirizzo di fqual = " << (unsigned long) p_fqual << endl;<br />
cout << "Indirizzo di p_fqual = " << (unsigned long) &p_fqual << endl;<br />
cout << "Indirizzo di p2_fqual = "<br />
<< (unsigned long) p2_fqual << endl << endl;<br />
}</pre><br />
Questo è il risultato che viene a me – i vostri numeri potrebbero essere completamente diversi.<br />
<br />
<br/>[[File:Qt IV 33.png|Qt_IV_33.png]]<br />
<br />
<br/>Ok, sono un sacco di numeri, però se li osserviamo bene ci forniscono anche un sacco di informazioni.<br />
<br />
Quello che abbiamo chiesto, e ottenuto, è l’indirizzo di memoria di tutte le variabili dichiarate, ivi compresi i puntatori e le variabili globali.<br />
<br />
Proviamo a spostare le righe ottenute in base all’indirizzo di memoria. Finiamo per trovarci in questa situazione:<br />
<br />
<br />
<br />
{| class="wikitable"<br />
|-<br />
| variabile globale<br />
| 134520885<br />
|-<br />
| oggetto ‘''new''’ in ''main()''<br />
| 156848136<br />
|-<br />
| oggetto ‘''new''’ in ''indagineSuNew()''<br />
| 156848152<br />
|-<br />
| variabile in ''indagineSuNew()''<br />
| 3219612663<br />
|-<br />
| puntatore in ''indagineSuNew()''<br />
| 3219612664<br />
|-<br />
| variabile in ''main()''<br />
| 3219612711<br />
|-<br />
| puntatore in ''main()''<br />
| 3219612712<br />
|}<br />
<br />
<br/>Cosa ci suggerisce questa tabella?<br />
<br />
A me sembra voglia dire che, anche se sono definiti in funzioni diverse, gli oggetti creati tramite ''new'' si vanno a posizionare in un’area di memoria che è distante da quella usata dalle funzioni, e più vicina a quella usata dagli oggetti globali. In altre parole, pare che gli oggetti creati con ''new'' godano di speciali privilegi, tra cui quello di dimorare in un’area di memoria diversa da quella in cui operano le ‘normali’ variabili definite all’interno delle funzioni.<br />
<br />
<br/>Bene, questa apparenza è una realtà di fatto e ha una conseguenza molto importante, ossia che gli oggetti creati con ''new'' '''NON''' muoiono insieme alla funzione. Giacché risiedono in uno spazio di memoria separato, quando una funzione viene conclusa il compilatore non si occupa di loro: esso si limita a rimettere lo spazio di memoria della funzione nel grande mucchio di quella utilizzabile, ma non va a ‘inseguire’ gli oggetti creati con ''new'' per recuperare anche i loro indirizzi di memoria.<br />
<br />
Dicendo la stessa cosa al positivo, ''new'' crea degli oggetti che sopravvivono alla distruzione della funzione all’interno della quale sono stati dichiarati, pertanto possono essere puntati con tranquillità anche dopo.<br />
<br />
Di conseguenza, recuperando e modificando il codice scritto in precedenza, il seguente programmino non solo non dà errori in fase di compilazione, ma è anche formalmente corretto (anche se pressoché inutile, ma questo non ci interessa):<br />
<pre>#include <iostream><br />
<br />
using std::cout;<br />
using std::endl;<br />
<br />
int* restUnInt();<br />
void qualcheOperazione();<br />
<br />
int main()<br />
{<br />
int* valRitorno;<br />
<br />
valRitorno = restUnInt();<br />
cout << "valRitorno = " << *valRitorno << endl;<br />
<br />
qualcheOperazione();<br />
<br />
cout << "valRitorno = " << *valRitorno << endl << endl;<br />
}<br />
<br />
int* restUnInt()<br />
{<br />
int* daRestituire = new int; // new non e' solo per gli oggetti!<br />
*daRestituire = 47;<br />
<br />
return daRestituire;<br />
}<br />
<br />
void qualcheOperazione()<br />
{<br />
int i1 = 7; // un numero a caso<br />
int i2 = 19; // un numero a caso<br />
<br />
cout << "7 x 19 = " << i1 * i2 << endl;<br />
}</pre><br />
L’oggetto puntato da ‘daRestituire’ è ancora perfettamente in forma dopo la distruzione di restUnInt(), giacché ne ha sentito solo una lontana eco, perciò può continuare a essere puntato da ‘valRitorno’ senza controindicazioni.<br />
<br />
<br/>Questo aggiunge un altro tassello alla riflessione che facevamo prima: se creiamo un oggetto con ''new'', otteniamo qualcosa che possiamo riuscire a usare come se fosse globale senza esserlo, anche perché '''il compilatore non si occupa mai di distruggerlo'''!<br />
<br />
Quindi, a differenza delle variabili globali, può essere creato in qualsiasi punto del programma e da lì vivere fino alla fine.<br />
<br />
<br/>Insomma, questo operatore ''new'' pare proprio una gran cosa. Viene da domandarsi come abbiamo fatto a farne fin’ora a meno.<br />
<br />
È proprio il caso di andare a vedere perché può arrivare a devastare anche il programma meglio progettato.<br />
<br />
<br />
<br />
== Perdere la memoria ==<br />
<br />
Cos’è dunque che fa ''new''? Crea un oggetto in memoria e restituisce un puntatore.<br />
<br />
Non sembra una cosa molto pericolosa.<br />
<br />
Bisogna prestare però attenzione al secondo dettaglio: l’oggetto non sarà mai distrutto. Le conseguenze sono abbastanza chiare: la memoria da lui occupata non tornerà più disponibile.<br />
<br />
<br/>Vi sembra un problema molto tecnico? Beh, in effetti stiamo scrivendo programmini così brevi che la memoria che andiamo a impegnare è una minuscola frazione di quella disponibile in un computer moderno, ma non è certo questa la situazione tipica di chi sceglie il C++ come linguaggio di sviluppo.<br />
<br />
Proviamo a immaginare una situazione in cui un oggetto viene creato con ''new'' in una funzione che viene ciclicamente invocata durante l’esecuzione del programma. Ogni volta il puntatore all’oggetto creato con ''new'' verrà distrutto all’uscita, ma l’oggetto no, pertanto a ogni chiamata ne verrà creato uno nuovo. A seconda del numero di chiamate e delle dimensioni dell’oggetto creato si potrebbe in poco tempo giungere a esaurire tutta la memoria disponibile. Nel momento in cui il programma chiede troppa memoria, il sistema operativo si difende chiudendolo in modo forzato.<br />
<br />
Simpatico, vero?<br />
<br />
<br/>Qualcuno forse a questo punto si starà grattando la testa pensieroso. Possibile che a una fascinosa invenzione come ''operator new'' non sia stata fornita una qualche utilità che consenta di usarla senza danni?<br />
<br />
Beh, in effetti sono stato un po’ drammatico. Non avrei dovuto dire che l’oggetto non sarà mai più distrutto, ma piuttosto che il compilatore non prenderà mai l’iniziativa di distruggerlo.<br />
<br />
Non è una finezza verbale: intendo dire che il compilatore di sua iniziativa non lo distruggerà, ma noi possiamo obbligarlo a farlo. Esiste in fatti l’opposto dell’operatore ''new'', che è ''delete''.<br />
<br />
<br/>''delete'' distrugge un oggetto creato con ''new''.<br />
<br />
La sua sintassi è molto semplice:<br />
<pre>Robot *p_robot = new Robot;<br />
delete p_robot;</pre><br />
Niente di più.<br />
<br />
<br/>Allora è semplicissimo. Tutto risolto, quindi? Possiamo usare ''new'' a piacere?<br />
<br />
In teoria sì, in pratica potrebbe non essere così semplice: vista la quantità di domande che si trovano su questo argomento nei forum, direi che un sacco di gente si trova in difficoltà a usare ''new'' e ''delete'', perciò forse conviene dar loro una seconda occhiata.<br />
<br />
<br/>Anche se stiamo di nuovo parlando di memoria e puntatori, l’argomento non è difficile. Il difficile è magari applicarlo nella pratica. Il fatto, detto papale papale, è che è davvero molto molto semplice dimenticarsi di ''delete''. Sembra una sciocchezza, ma è così. Vediamo perché.<br />
<br />
<br/>Intanto mettiamoci d’accordo su una regola generale: '''tutti''' gli oggetti creati con ''new'' devono essere distrutti; o, con altre parole, su '''tutti''' gli oggetti creati con ''new'' bisogna ricordarsi di usare ''delete''.<br />
<br />
<br/>Quella sopra è una regola ineludibile. Insisto: il C++ non offre il meglio di sé quando un singolo programmatore progetta un piccolo software; il C++ è uno strumento eccezionale per un gruppo che vuole tirar su un progetto di una certa dimensione. I vostri colleghi borbotteranno se cominciate a lasciare oggetti inutilizzati in memoria.<br />
<br />
Però le cose non sono così semplici. Poniamo il caso di iniziare a lavorare su una parte del codice a inizio settimana. Poi capita il classico imprevisto che costringe a lasciare tutto lì per qualche giorno mentre si devono portare avanti altre cose. Alla fine si può riprendere in mano il codice di giorni o settimane prima, ma… A quel punto chi se lo ricorda più che in qualcuna di quelle decine e decine di righe avevamo lasciato un ''new'' in sospeso?<br />
<br />
<br/>Il fatto è, cercate di immaginare la situazione, che il codice funziona benissimo. Non ci sono difetti!<br />
<br />
Il mancato uso di ''delete'' è uno di quei vizi subdoli e nascosti che fanno dannare a ritrovarli. La gestione della memoria è, in generale, uno di quegli argomenti su cui sono state spesi fiumi di parole.<br />
<br />
Vediamo se ci sono delle soluzioni semplici a questa istintiva e universale tendenza alla pasticcioneria.<br />
<br />
<br/>Una delle più simpatiche che ho sentito è stata: basta scrivere '''subito''' l’istruzione ''delete''. In altre parole, quando creiamo un oggetto con ''new'', al rigo sotto lo distruggiamo subito con ''delete'', salvo poi spostare quest’ultima istruzione in basso via via che aggiungiamo codice fra le due.<br />
<br />
L’idea è carina e non ho nulla da obiettare, a parte la scomodità. Però si può, oltre ad applicare questa se piace, anche cercare di farci qualche domanda ''prima'' di usare ''new''.<br />
<br />
<br/>Infatti la questione è: perché mi serve ''new''?<br />
<br />
Si potrebbe pensare a un mero problema di comodità. Invece di scrivere:<br />
<pre>Robot miorobot("Mario");<br />
Robot* p_miorobot = &miorobot;</pre><br />
scrivo solo:<br />
<pre>Robot* p_miorobot = new Robot("Mario");</pre><br />
e risparmio un rigo.<br />
<br />
Chi la pensa così probabilmente sta leggendo troppo di corsa questi paragrafi. In realtà non rispalmiamo niente perché prima o poi dovremo scrivere:<br />
<pre>delete p_miorobot;</pre><br />
perciò, due righe nel primo caso, due righe nel secondo… abbiamo fatto pari.<br />
<br />
<br/>L’altra possibilità, che mi sembra più frequente, è quella in cui abbiamo bisogno di un oggetto che decideremo noi quando morirà.<br />
<br />
Ecco: questa è un’esigenza ''vera'', e non soltanto la ricerca di una comodità. Ma quando può capitare una cosa del genere? Beh, l’esempio classico è nell’interazione con l’utente.<br />
<br />
Immaginate di stare lavorando sul vostro programma di videoscrittura preferito. A un certo punto siete costretti a lasciare in sospeso quello che stavate facendo e a scrivere una cosa diversa. quale che sia il programma che state usando, è assai probabile che abbia un comando del tipo File → Nuovo documento. Scegliendo quel comando, vi si apre una nuova pagina bianca che va a coprire quella su cui stavate lavorando. E se lo selezionate di nuovo, si aprirà ancora un nuovo “documento”.<br />
<br />
<br/>Quel che il comando fa è di invocare una funzione (che molto probabilmente sarà un metodo di una ''class'') la quale crea una nuova istanza “documento”. Finito il lavoro di creazione, la funzione si conclude, ma il nuovo “documento” '''non deve morire con lei'''! Anzi! Potrebbe essere che gli sia richiesto di rimanere disponibile fino alla chiusura del programma.<br />
<br />
A me sembrerebbe la situazione ideale per utilizzare ''new'': posso creare un nuovo oggetto direttamente dentro una funzione, ma sapendo che rimarrà in vita finché non lo distruggerò io; non solo, ma posso renderlo visibile al resto del programma con semplicità restituendo un puntatore, ossia un modesto intero che occupa pochissima memoria. Se l’avessi creato con il metodo ‘tradizionale’ il computer si sarebbe dovuto occupare di fare una costosissima (in termini di tempo e risorse) copia per la funzione chiamante.<br />
<br />
<br/>Se avete colto l’essenza dell’esempio precedente, non vi sorprenderà sentir dire che molto spesso ''new'' è usato all’interno delle ''class''. Infatti questo rende possibile scrivere tutte le istruzioni ''delete'' che servono dentro il distruttore.<br />
<br />
L’idea di fondo è che, male che vada, quando l’istanza di ''class'' viene distrutta, l’invocazione del metodo distruttore comporterà l’esecuzione di tutte le funzioni ''delete'' in esso contenute, quindi, anche se ci fossimo dimenticati di distruggere qualche oggetto al momento giusto, almeno a quel punto sarà distrutto.<br />
<br />
<br/>Con questo possiamo lasciare anche ''new'' e ''delete''.<br />
<br />
<br />
<br />
= Per chi non ce l’avesse fatta =<br />
<br />
Quel che segue è il codice di Robot2 nel caso qualcuno non fosse riuscito a dividerlo correttamente nei vari file.<br />
<br />
<br/>file “robot.h”<br />
<pre>#ifndef ROBOT_H<br />
#define ROBOT_H<br />
<br />
#include<iostream><br />
<br />
using std::string;<br />
<br />
class Robot<br />
{<br />
string nome;<br />
int carica;<br />
int x;<br />
int y;<br />
<br />
public:<br />
Robot();<br />
Robot(string pa_nome);<br />
void setNome(string battezza);<br />
string getNome();<br />
void vaiSu();<br />
void vaiGiu();<br />
void vaiSx();<br />
void vaiDx();<br />
void datiASchermo();<br />
~Robot();<br />
};<br />
<br />
#endif // ROBOT_H</pre><br />
File “robot.cpp”<br />
<pre>#include "robot.h"<br />
<br />
using std::cout;<br />
using std::endl;<br />
<br />
Robot::Robot()<br />
{<br />
nome = "Senza nome";<br />
x = 0;<br />
y = 0;<br />
carica = 100;<br />
}<br />
<br />
Robot::Robot(string pa_nome)<br />
{<br />
nome = pa_nome;<br />
x = 0;<br />
y = 0;<br />
carica = 100;<br />
}<br />
<br />
void Robot::setNome(string battezza)<br />
{<br />
nome = battezza;<br />
}<br />
<br />
string Robot::getNome()<br />
{<br />
return nome;<br />
}<br />
<br />
void Robot::vaiSu()<br />
{<br />
y += 1;<br />
carica -= 5;<br />
}<br />
<br />
void Robot::vaiGiu()<br />
{<br />
y -= 1;<br />
carica -= 5;<br />
}<br />
<br />
void Robot::vaiSx()<br />
{<br />
x -= 1;<br />
carica -= 5;<br />
}<br />
<br />
void Robot::vaiDx()<br />
{<br />
x += 1;<br />
carica -= 5;<br />
}<br />
<br />
void Robot::datiASchermo()<br />
{<br />
cout << "Robottino '" << nome << "':" << endl;<br />
cout << " posizione: x = " << x << ", y = " << y << endl;<br />
cout << " carica residua: " << carica << "%" << endl;<br />
cout << endl << endl;<br />
}<br />
<br />
Robot::~Robot()<br />
{<br />
cout << endl << endl;<br />
cout << "Torna presto a trovarci!" << endl << endl;<br />
}</pre><br />
File “main.cpp”:<br />
<pre>#include <iostream><br />
#include <robot.h><br />
<br />
using std::cin;<br />
using std::cout;<br />
using std::string;<br />
<br />
int muoviRobot(Robot &rbt);<br />
<br />
int main()<br />
{<br />
Robot rbt("Mario");<br />
// rbt.setNome("Mario");<br />
<br />
while(muoviRobot(rbt))<br />
rbt.datiASchermo();<br />
<br />
return 0;<br />
}<br />
<br />
int muoviRobot(Robot &rbt)<br />
{<br />
string testo;<br />
cout << "Direzione? ";<br />
cin >> testo;<br />
<br />
if("a" == testo) {<br />
rbt.vaiSx();<br />
return 1;<br />
} else if ("w" == testo) {<br />
rbt.vaiSu();<br />
return 1;<br />
} else if ("s" == testo) {<br />
rbt.vaiDx();<br />
return 1;<br />
} else if ("z" == testo) {<br />
rbt.vaiGiu();<br />
return 1;<br />
} else if ("0" == testo) {<br />
return 0;<br />
}<br />
return 2; // 2 == tasto non riconosciuto<br />
}</pre><br />
Ci trovate qualcosa di strano?<br />
<br />
In effetti uno dei metodi si è duplicato: il costruttore ''Robot()''. Adesso pare che ne esistano due versioni…<br />
<br />
Beh, è vero fino a un certo punto. Si tratta di una caratteristica del C++ che sono stato indeciso fino a qui se trattare o no, e alla fine ho deciso per un compromesso: la accenno soltanto&nbsp;:-)<br />
<br />
<br/>Si tratta di un meccanismo che si chiama ''overload'' di funzione e non è difficile.<br />
<br />
In pratica, nel C++ una funzione non si riconosce '''soltanto''' dal suo nome, ossia dall’etichetta scritta prima della parentesi tonda, ma '''anche''' dai suoi argomenti.<br />
<br />
Quindi se ci sono due funzioni con lo stesso nome, ma con argomenti differenti, per il compilatore si tratta di funzioni differenti e possono coesistere nello stesso spazio di visibilità.<br />
<br />
<br/>Nel nostro caso, il metodo costruttore ''Robot()'' '''senza argomenti''' è, per il compilatore, una funzione diversa da ''Robot(string)'' che ha '''un argomento di tipo ''string'''''.<br />
<br />
Quindi, se all’atto della creazione dell’istanza di classe viene scritto:<br />
<pre>Robot rbt("Mario");</pre><br />
come nel nostro caso, verrà invocato il metodo costruttore Robot(string).<br />
<br />
Se invece venisse scritto:<br />
<pre>Robot rbt;</pre><br />
l’oggetto verrebbe creato regolarmente tramite il metodo Robot(), il quale assegna alla proprietà ‘nome’ il testo “Senza nome”.<br />
<br />
<br/>Anche se non fosse del tutto chiaro, non vi preoccupate: ne riparleremo usando le librerie Qt.<br />
<br />
Che è ciò che ci apprestiamo a fare (anche se dovremo fare prima i conti con l’ereditarietà).<br />
[[Category:C++|Category:C++]]</div>
Robi
https://kata.coderdojo.it/wiki/index.php?title=Tutorial:_Accometaggio_Philae
Tutorial: Accometaggio Philae
2014-12-16T21:45:15Z
<p>Fpiantini: </p>
<hr />
<div>== Gioco ACCOMETAGGIO PHILAE (mentor) ==<br />
<br />
Questo gioco vuole essere un omaggio alla missione Rosetta dell'Agenzia Spaziale Europea e in particolare al lander Philae che nel novembre 2014 ci ha tenuto tutti con il fiato sospeso mentre atterrava su una cometa.<br />
<br />
Scopo del gioco è quello di riuscire a far atterrare Philae su un punto preciso della superficie della cometa utilizzando un unico getto d'aria che fornisce una spinta verso il basso (esattamente come è avvenuto nella realtà!).<br />
<br />
Per realizzare il tutto si è preso pesantemente spunto da un [http://www.bbc.com/news/science-environment-29746430 gioco messo online dalla BBC] nei giorni dell'accometaggio di Philae.<br />
<br />
Il gioco in formato Scratch 2.0 con il presente tutorial in formato PDF i immagini di supporto da utilizzare durante la riscrittura del progetto durante una sessione Coderdojo è presente su questo wiki: [[File:040 philae gioco scratch.zip]]·<br />
<br />
<br />
<br />
=== Creazione dello Stage (sfondo) ===<br />
<br />
Ci vuole uno sfondo "spaziale" con in basso la rappresentazione del suolo della cometa. Come sfondo di partenza si può utilizzare ad esempio lo sfondo "Stars" presente nella libreria Scratch disegnando a mano (utilizzando pennello e riempimento varie linee di livello del suolo della cometa con un risultato simile a quello riportato nella figura qui sotto.<br />
<br />
[[File:Philae sfondo.png|File:Philae_sfondo.png]]<br />
<br />
In alternativa si possono utilizzare gli sfondi di libreria "Space" o "Moon" in cui la superficie della cometa non ha bisogno di essere disegnata.<br />
<br />
<br />
<br />
<br />
<br />
=== Preparazione del sito di atterraggio ===<br />
<br />
Scegliere un punto della cometa alla sinistra e disegnare uno o due sprite costituiti da due cerchi circa concentrici di cui il più interno deve essere piccolo e di un colore ben riconoscibile. L'unico script associato a questo sprite è quello che all'avvio lo posiziona alle coordinate desiderate. Il risultato finale deve essere simile alla figura riportata nel seguito.<br />
<br />
[[File:Philae cometa con sito atterraggio.png|Philae_cometa_con_sito_atterraggio.png]]<br />
<br />
Ecco invece lo script (in fase di realizzazione potrebbe essere necessario ottimizzare le coordinate in base a quanto realizzato dal bambino).<br />
<br />
[[File:Philae script sito atterraggio.png|Philae_script_sito_atterraggio.png]]<br />
<br />
=== Il lander Philae: disegno dello sprite ===<br />
<br />
Eccoci al protagonista del nostro gioco, il lander Philae. Per prima cosa va disegnato o completamente a mano o utilizzando l'immagine fornita:<br />
<br />
[[File:Philae Lander.png|Philae_Lander.png]]<br />
<br />
Se si decide di disegnarlo "a mano" si può andare di fantasia, disegnando un veicolo spaziale liberamente purché più o meno della giusta dimensione. Si può anche utilizzare lo sprite "Spaceship" presente nella libreria standard Scratch.<br />
<br />
=== Il lander Philae: il movimento ===<br />
<br />
Philae deve partire in alto a destra e scendere verso il sito di atterraggio senza colpirlo però perfettamente. Lo script è molto semplice. A parte la sezione iniziale in cui lo sprite viene posizionato alle coordinate appropriate, lo script è un semplice loop infinito in cui si cambiano le coordinate X e Y dei valori appropriati per percorrere il percorso desiderato.<br />
<br />
Per rendere più realistico il gioco si utilizzano i seguenti accorgimenti:<br />
<br />
*All'inizio il lander parte con una dimensione ridotta (per esempio del 50%) e via via si ingrandisce in modo da dare l'illusione dell'avvicinamento. Per ottenere questo nel loop principale dello script oltre al cambio di coordinate si effettua un "cambio dimensione"<br />
<br />
*Per rendere più aleatorio (spiegare il significato della parola aleatorio ai bambini!) il moto, non cambiare le coordinate X e Y di un valore costante ma utilizzare la generazione di numeri casuali<br />
<br />
Far "giocare" i bambini in modo da scegliere appropriatamente i valori di spostamento X e Y e di cambio dimensione in modo da ottenere il moto voluto. Alla fine lo script deve risultare qualcosa di simile a questo:<br />
<br />
[[File:Philae script moto.png|Philae_script_moto.png]]<br />
<br />
=== Il lander Philae: l'accometaggio ===<br />
<br />
L'accometaggio può riuscire o fallire a seconda che Philae riesca o no a toccare la parte interna dello sprite colorato posto sulla superficie della cometa. Se invece si arriva sul bordo allora l'atterraggio è fallito. Per comunicare efficamente la riuscita o meno dell'atterraggio si possono utilizzare dei suoni, uno "brillante" e positivo per comunicare il successo, uno "disarmonico" per indicare l'insuccesso.<br />
<br />
[[File:Philae script accometaggio riuscito e no.png|Philae_script_accometaggio_riuscito_e_no.png]]<br />
<br />
Se nella sezione precedente (movimento) si sono scelti opportuni parametri a questo punto l'accometaggio dovrebbe sempre fallire (Philae dovrebbe passare sempre sopra il sito di atterraggio e arrivare al bordo sinistro dello stage<br />
<br />
=== Il lander Philae: il pilotaggio ===<br />
<br />
A questo punto rimane da rendere interattivo il gioco aggiungendo la possibilità di pilotare Philae. Nella versione iniziale del tutorial si prevede solo la possibilità di attivare un getto sulla parte superiore del lander che fornisce allo stesso una spinta verso il basso.<br />
<br />
Occorre quindi effettuare le seconde operazioni:<br />
<br />
*realizzare un secondo costume per lo sprite Philae con disegnato uno "sbuffo" sulla parte superiore. Replicare il primo costume e disegnare delle linee sopra il "tetto del lander". Qualcosa di simile all'immagine riportata sotto:<br />
<br />
[[File:Philae con sbuffo.png|Philae_con_sbuffo.png]]<br />
<br />
*realizzare uno script di movimento che, all'interno di un loop infinito, controlla se viene premuto uno specifico tasto (per esempio freccia su o freccia giù) e se sì cambia Y di un numero generato a caso. Nello script vengono anche alternati i due costumi per dare l'illusione del funzionamento del propulsore. Durante l'accensione dei propulsori riprodurre anche qualche effetto sonoro (anche se a rigore nello spazio i suoni non si sentono!!).<br />
<br />
[[File:Philae script pilotaggio.png|Philae_script_pilotaggio.png]]<br />
<br />
=== Estensioni & Esercizi ===<br />
<br />
Questo gioco si presta a varie modifiche ed esercizi fino a farlo diventare un clone del mitico [http://moonlander.seb.ly/ Lunar Lander] creato da Atari nel 1979, "[http://www.technologizer.com/2009/07/19/lunar-lander/ One giant step for gamekind]". Esiste anche un'interessantissima [http://scratch.mit.edu/projects/210916/ versione Scratch]!<br />
[[Category:Scratch|A]]</div>
Fpiantini
https://kata.coderdojo.it/wiki/index.php?title=Earth3D
Earth3D
2014-12-16T10:48:06Z
<p>Mbert: </p>
<hr />
<div>= '''La terra in 3D''' =<br />
<br />
Come ho pensato lo sviluppo dell'esempio.<br />
<br />
Occorre copiare lo zip [[Media:Earth3D.zip|Earth3D.zip]]&nbsp;e il file delle immagini aggiuntive [[Media:Earth3DImmaginiAdd.zip|Earth3DImmaginiAdd.zip]] sulla macchina del coderNinja.<br />
<br />
Il file&nbsp;<tt>EarthFinale.html</tt>&nbsp;è il risultato alla fine del tutorial.<br />
<br />
Il file&nbsp;<tt>EarthStart.html</tt> è la base di partenza e nel seguito faccio riferimento ad esso, in copia qui sotto.<br />
<pre><!DOCTYPE html><br />
<html><br />
<head><br />
<meta charset="utf-8" /><br />
<title>Il Mondoooo</title><br />
<style><br />
body {<br />
margin: 0px;<br />
padding: 0px;<br />
}<br />
</style><br />
<script src="js/three.min.js"></script><br />
<script src="js/TrackballControls.js"></script><br />
<script src="js/coderDojoLib.js"></script><br />
</head><br />
<body onload="start()"><br />
<script><br />
var canvas3d, r = 16;<br />
function start() {<br />
canvas3d = new cdRender3d();<br />
<br />
var geometry = new THREE.SphereGeometry(r, 32, 32);<br />
var material = new THREE.MeshBasicMaterial( { color: 0x0000ff } );<br />
<br />
canvas3d.addMesh(geometry, material);<br />
<br />
<br />
canvas3d.runRender();<br />
}<br />
<br />
// 1 Step<br />
// var material = new THREE.MeshPhongMaterial();<br />
// canvas3d.addLight();<br />
// canvas3d.addSpot(0xaf9f8f, 0.3);<br />
<br />
// 2 Step<br />
// material.map = THREE.ImageUtils.loadTexture('img/earthmap1k.jpg', undefined, canvas3d.getRender());<br />
// material.bumpMap = THREE.ImageUtils.loadTexture('img/earthbump1k.jpg', undefined, canvas3d.getRender());<br />
// material.bumpScale = 0.6;<br />
// material.specularMap = THREE.ImageUtils.loadTexture('img/earthspec1k.jpg', undefined, canvas3d.getRender());<br />
// material.specular = new THREE.Color('grey');<br />
//<br />
<br />
// Alternative<br />
// riga 20 //canvas3d = new cdRender3d({ctrl: true});<br />
// riga 22<br />
//var geometry = new THREE.OctahedronGeometry(r, 0);<br />
//var geometry = new THREE.DodecahedronGeometry(r, 0);<br />
//var geometry = new THREE.BoxGeometry(r, r, r);<br />
//var geometry = new THREE.TorusGeometry( r, 0.4 * r, 32, 64 );<br />
<br />
// riga 25 //material.map = THREE.ImageUtils.loadTexture('img/BabyTux.png', undefined, canvas3d.getRender());<br />
<br />
<br />
// posizioni GPS di Firenze, Parigi, Londra, New York, Sidney<br />
//var parameters = [ <br />
// [ 43.771417, 11.253836, 1.4 ], <br />
// [ 48.859405, 2.353880, 1.1 ],<br />
// [ 51.518809, -0.127056, 1.3 ],<br />
// [ 40.735661, -73.996460, 1.5 ],<br />
// [ -33.849974, 151.208077, 1.2 ],<br />
//];<br />
<br />
// Riga 45 //canvas3d.addPositions(parameters);<br />
<br />
</script><br />
</body><br />
</html><br />
<br />
</pre><br />
== Partenza ==<br />
<br />
Il file base crea una palla o meglio un cerchio blu su sfondo nero.<br />
<br />
Cambiando il valore di color alla riga 23 si cambia il colore della palla<br />
<br />
== Passo 1) ==<br />
<br />
Commento riga 23 e aggiungo la prima riga di step1<br />
<br />
--> var material = new THREE.MeshPhongMaterial();<br />
<br />
Tutto nero, manca una luce<br />
<br />
Aggiungo a riga 28 una luce, la seconda riga di step1<br />
<br />
--> canvas3d.addLight();<br />
<br />
Ricompare un cerchio (bianco grigio), il colore si può cambiare passando il valore numerico in addLight es: 0xc2 è blu, 0xc20000 è rosso.<br />
<br />
In partenza è stato usato un materiale base che ha un colore, adesso usiamo un materiale riflettente, quindi serve una luce per vederlo.<br />
<br />
L'impressione è ancora piatta, aggiungiamo un faretto per creare l'effetto 3D con luci e ombre.<br />
<br />
Aggiungo a riga 29 un faretto, la terza riga di step1<br />
<br />
--> canvas3d.addSpot(0xaf9f8f, 0.3);<br />
<br />
Il primo parametro è il colore, il secondo l'intensità.<br />
<br />
Notate che il faretto sta ruotando intorno alla sfera.<br />
<br />
== Passo 2) ==<br />
<br />
Diamo l'aspetto della terra alla sfera.<br />
<br />
Aggiungo a riga 25 la texture della terra, la prima riga di step2<br />
<br />
--> material.map = THREE.ImageUtils.loadTexture('img/earthmap1k.jpg', undefined, canvas3d.getRender());<br />
<br />
Cambiando la riga 20 ovvero aggiungendo il parametro {ctrl: true}, passiamo dalla rotazione automatica a quella manuale.<br />
<br />
Trascinando (btn sinistro) il mouse la terra ruota, con la rotella si fa lo zoom.<br />
<br />
Aggiungo a riga 26 e 27 la rugosità, la seconda e terza riga di step2<br />
<br />
--> material.bumpMap = THREE.ImageUtils.loadTexture('img/earthbump1k.jpg', undefined, canvas3d.getRender());<br />
<br />
--> material.bumpScale = 0.6;<br />
<br />
Il parametro bumpScale dà la proporzione di 'rugosità' definita nella texture.<br />
<br />
Aggiungo a riga 28 e 29 l'effetto specchio, la quarta e quinta riga di step2<br />
<br />
--> material.specularMap = THREE.ImageUtils.loadTexture('img/earthspec1k.jpg', undefined, canvas3d.getRender());<br />
<br />
--> material.specular = new THREE.Color('grey');<br />
<br />
<br />
<br />
== Alternative ==<br />
<br />
Nello step alternative ho messo alcune modifiche oltre al già citato controllo manuale, e ai giochi con i colori<br />
<br />
Cambiando la gemetria, dalla sfera al toro ...<br />
<br />
Cambiando le texture o cambiando pianeta (le mappe sono prese da [http://planetpixelemporium.com/earth.html http://planetpixelemporium.com/earth.html])<br />
<br />
== Step aggiuntivo. ==<br />
<br />
Date delle posizioni GPS il comando addPositions le mostra sulla sfera<br />
[[Category:Javascript|T]]</div>
Mbert
https://kata.coderdojo.it/wiki/index.php?title=Tutorial_C%2B%2B_con_Qt_-_Parte_III
Tutorial C++ con Qt - Parte III
2014-12-04T14:01:05Z
<p>Robi: </p>
<hr />
<div>= Tutorial C++ con le librerie Qt – Parte III =<br />
<br />
== Puntatori e references ==<br />
<br />
=== Soluzione al problema del tutorial precedente ===<br />
<br />
Avete risolto il problema con cui ci siamo lasciati nell’ultimo tutorial?<br />
<br />
Per chi non ce l’avesse fatta, ecco qui una possibile soluzione:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
void spiegazioni();<br />
int mossaCane(int fiammiferi);<br />
int mossaAnatra(int fiammiferi);<br />
<br />
int main()<br />
{<br />
spiegazioni();<br />
int fiammiferi = 21;<br />
<br />
do {<br />
fiammiferi = mossaCane(fiammiferi);<br />
fiammiferi = mossaAnatra(fiammiferi);<br />
} while ( 1 < fiammiferi );<br />
<br />
cout << endl << "* * * * * * * * * * * * * * * * * * * * * * * * * * *"<br />
<< endl;<br />
cout << "Mi spiace, sei rimasto con l'ultimo"<br />
" fiammifero..." << endl;<br />
cout << "Ho vinto io." << endl;<br />
cout << "* * * * * * * * * * * * * * * * * * * * * * * * * * *"<br />
<< endl << endl;<br />
<br />
return 0;<br />
}<br />
<br />
void spiegazioni()<br />
{<br />
cout << "Ci sono 21 fiammiferi." << endl;<br />
cout << "Ne possiamo prendere da 1 a 4 per volta." << endl;<br />
cout << "Chi rimane con l'ultimo ha perso." << endl;<br />
cout << endl << "Hai la prima mossa." << endl << endl;<br />
}<br />
<br />
int mossaCane(int fiammiferi)<br />
{<br />
int presa = 0;<br />
<br />
while ( presa < 1 || presa > 4 ){<br />
<br />
cout << "Quanti fiammiferi prendi (da 1 a 4)? " << endl;<br />
cin >> presa;<br />
<br />
if( presa < 1 || presa > 4) {<br />
cout << "Spiacente. Devi prendere almeno un fiammifero, "<br />
"ma non più di quattro..." << endl << endl;<br />
}<br />
<br />
}<br />
<br />
fiammiferi -= presa;<br />
cout << "Hai preso " << presa << " fiammiferi." << endl;<br />
cout << "Ne rimangono " << fiammiferi << "." << endl;<br />
<br />
return fiammiferi;<br />
}<br />
<br />
int mossaAnatra(int fiammiferi)<br />
{<br />
int presa;<br />
<br />
if( 1 < fiammiferi ) {<br />
presa = fiammiferi - 1;<br />
}<br />
if( 6 < fiammiferi ) {<br />
presa = fiammiferi - 6;<br />
}<br />
if( 11 < fiammiferi ) {<br />
presa = fiammiferi - 11;<br />
}<br />
if( 16 < fiammiferi ) {<br />
presa = fiammiferi - 16;<br />
}<br />
<br />
fiammiferi -= presa;<br />
<br />
cout << "Io prendo " << presa << " fiammiferi." << endl;<br />
cout << "Adesso ne rimangono " << fiammiferi << "." << endl<br />
<< endl;<br />
<br />
return fiammiferi;<br />
}</pre><br />
Il codice è rimasto pressoché identico, salvo che adesso le due funzioni più importanti ricevono valori in ingresso e restituiscono valori in uscita.<br />
<br />
Qualcuno è rimasto sorpreso del vedere usare sempre la variabile fiammiferi in ogni funzione?<br />
<br />
Beh, non c’è nulla di insolito: stiamo tenendo il conto del numero di fiammiferi, quindi non c’è nulla di strano a chiamarla ‘fiammiferi’ o ‘num_fiammiferi’ o altri nomi simili. Quel che bisogna tenere presente, però, è che '''non''' si tratta sempre della stessa variabile. Infatti ‘fiammiferi’ è dichiarata all’interno di ''main()'', pertanto è una variabile '''locale''': esiste solo dentro ''main()'' e non può essere ''vista'' da altre funzioni.<br />
<br />
Ribadiamo il concetto: se una variabile è locale, allora nella altre funzioni possono esistere altre variabili con lo stesso nome e, finché saranno tutte locali, '''non''' si daranno noia fra di loro. Saranno a tutti gli effetti variabili diverse, il computer non le mischierà, esattamente come il nome Mario sulla vostra rubrica potrebbe riferirsi a Mario Rossi mentre il nome Mario sulla rubrica di un vostro amico potrebbe essere quello di Mario Bianchi.<br />
<br />
<br/>Vi ricordate cosa abbiamo detto fin dall’inizio riguardo al passare un valore a una funzione? Il valore che passiamo finisce dentro la variabile che è indicata nelle parentesi accanto al nome. Per cui se scrivo:<br />
<pre>void funzione_qualsiasi_n_1()<br />
{<br />
int una_variabile = 100;<br />
funzione_qualsiasi_n_2(una_variabile);<br />
}<br />
<br />
void funzione_qualsiasi_n_2(int valore_ricevuto)<br />
{<br />
cout << "Ho ricevuto il valore " << valore_ricevuto << endl;<br />
}</pre><br />
Il risultato sarà la scritta:<br />
<pre>Ho ricevuto il valore 100</pre><br />
né più né meno che se avessi scritto:<br />
<pre>void funzione_qualsiasi_n_1()<br />
{<br />
int una_variabile = 100;<br />
funzione_qualsiasi_n_2();<br />
}<br />
<br />
void funzione_qualsiasi_n_2()<br />
{<br />
int valore_ricevuto = 100;<br />
cout << "Ho ricevuto il valore " << valore_ricevuto << endl;<br />
}</pre><br />
La differenza consiste ovviamente nel fatto che nel secondo caso le due funzioni non si ‘parlano’ fra di loro, bensì una si limita a chiamare l’altra senza passargli alcun valore.<br />
<br />
Nel primo caso invece quel che succede è che il compilatore crea, al momento della chiamata, la variabile ‘valore_ricevuto’ e vi inserisce il dato 100. Se ci chiedessero: «Dopo la chiamata, nella funzione ''funzione_qualsiasi_n_2()'' c’è o no una variabile ‘valore_ricevuto’ con valore 100?», dovremmo rispondere di sì in entrambi i casi.<br />
<br />
<br/>Fin qui dovrebbe essere semplice perché ne avevamo già parlato.<br />
<br />
Nella nostra nuova versione del gioco dei fiammiferi succede esattamente la stessa cosa.<br />
<br />
all’interno di ''main()'' troviamo l’istruzione<br />
<pre>int fiammiferi = 21;</pre><br />
che definisce una variabile locale ‘fiammiferi’ e la inizializza al valore 21.<br />
<br />
Da questo rigo in poi la variabile ‘fiammiferi’ è disponibile dentro ''main()'' e ne possiamo fare ciò che vogliamo.<br />
<br />
Quando viene chiamata ''mossaCane()'', le viene passato il valore della variabile fiammiferi.<br />
<br />
Se leggiamo com’è definita la funzione ''mossaCane()'', però, scopriamo che è definita così:<br />
<pre>int mossaCane(int fiammiferi)</pre><br />
<br/>Ciò significa che il compilatore creerà una nuova variabile, interna ('''locale'''!) alla funzione ''mossaCane()'', la chiamerà ‘fiammiferi’, stabilirà che può contenere solo valori interi, e le assegnerà il valore che ha lì con sé, ossia quello che ha letto nella variabile ‘fiammiferi’ di ''main()''.<br />
<br />
<br/>Di nuovo: stiamo creando variabili con lo stesso nome, ma queste variabili sono e rimarranno sempre indipendenti l’una dall’altra. Il computer si limiterà a COPIARE I VALORI di una all’interno dell’altra, per cui capiterà che ''in certi momenti'' i loro valori siano identici, ma per il computer si tratterà sempre di due variabili distinte.<br />
<br />
<br/>A noi esseri umani, invece, fa comodo aver la possibilità di riciclare i nomi, non solo perché così non ci dobbiamo preoccupare che qualcun altro, all’interno dello stesso programma, usi lo stesso nome, ma anche perché ci rende molto più facile ricordare, mesi dopo, perché diamine abbiamo creato quella variabile e a cosa ci servisse.<br />
<br />
<br/>Continuando a seguire il codice, scopriamo che alla fine di ''mossaCane()'' il computer torna in ''main()'', ma si porta dietro il VALORE della variabile locale ‘fiammiferi’<br />
<pre>return fiammiferi;</pre><br />
E chi c’è lì ad aspettare il valore? La variabile locale ‘fiammiferi’ di main(), la quale sostituirà il suo valore con quello ricevuto:<br />
<pre>fiammiferi = mossaCane(fiammiferi);</pre><br />
Capisco che, essendo noi abituati a leggere da sinistra verso destra, ci rimanga un po’ ostico comprendere che ciò che capita a destra del segno di uguale viene eseguito prima di ciò che capita a sinistra, ma è solo questione di farci l’abitudine.<br />
<br />
L’istruzione dice: «Ehi, Mister Compilator, inserisci il valore di ritorno della funzione ''mossaCane()'' nella variabile ‘fiammiferi’. Ah! A proposito, quando invochi la funzione ''mossaCane()'', ricordati di portarti dietro il valore che c’è adesso in ‘fiammiferi’». Il nostro computer, per sapere quale valore inserire in ‘fiammiferi’, non può far altro che seguire tutta ''mossaCane()'' fino all’istruzione ''return''.<br />
<br />
<br/>In realtà la cosa è così semplice che a continuare a parlarne corro il rischio di farla sembrare più complicata di quello che è.<br />
<br />
L’unica cosa su cui rimane da mettersi d’accordo è un altro parolone. Coraggio, questo è semplice&nbsp;:) Avete già digerito ‘invocare’ e ‘locale’, che sarà mai ‘parametro’? Beh, è solo il nome della variabile che si trova all’inizio della funzione, quella tra parentesi. Nel piccolo esempio di prima, ‘valore_ricevuto’ sarebbe stato un ''parametro''.<br />
<br />
Un ''parametro'' di una funzione è quindi una variabile come tutte, solo che non viene dichiarata dentro il ''corpo'' di una funzione, ossia il blocco fra le due parentesi graffe, bensì prima, fra le parentesi tonde; il suo scopo è ricevere i valori che arrivano dalle altre funzioni. Eccetto per questi due aspetti, un ''parametro'' si usa poi come tutte le altre variabili locali.<br />
<br />
<br/>Ah, dimenticavo! Anche il valore che viaggia fra una funzione e l’altra di solito viene chiamato con un nome particolare: argomento. La distinzione non è molto importante; se però abbiamo voglia di essere precisi, dovremmo usare il termine ''parametro'' per parlare della variabile che riceve il valore e il termine ''argomento'' per riferisci al valore medesimo. Se invece non fossimo sempre così precisi, una volta inteso che la differenza è minima riusciremo lo stesso a comprendere il senso di ciò che si legge.<br />
<br />
<br/>Avete visto con quanta poca fatica abbiamo eliminato una pericolosa variabile globale? Però possiamo fare di meglio; andiamo avanti.<br />
<br />
<br />
<br />
=== Indirizzi di memoria: vita e morte delle variabili ===<br />
<br />
==== Quando il numero è proprio grosso ====<br />
<br />
Dicevamo che il C++ offre altri strumenti per affrontare questo genere di problemi, ossia il passaggio di parametri, alcuni ereditati dal C (es. i puntatori), altri ripresi da altri linguaggi (es. i ''references''). Nessuno di questi due costrutti compare esplicitamente nel JavaScript perciò non potremo usare quel linguaggio come apripista. Possiamo però usarlo per sottolineare di nuovo le differenze con il C++, aspetto che può contribuire a chiarire i vari aspetti della questione.<br />
<br />
<br/>Intanto dobbiamo tornare a Qt, dove chiuderemo il progetto esistente e ne apriremo uno nuovo, con un nome generico che potrebbe essere “Prove”. Infatti ciò di cui andiamo a parlare presenta più di una sfaccettatura e, invece di creare un programma ‘completo’, seppur minimale, useremo spezzoni di codice. Pertanto ci serve una specie di lavagna che riuseremo più volte – altrimenti dovremmo creare tanti progettini minuscoli di poche righe, cosa che ci farebbe perdere un sacco di tempo.<br />
<br />
Non avete bisogno di indicazioni, ormai, per aprire un nuovo progetto: la directory rimane la solita, il nome è Prove.<br />
<br />
<br/>Per introdurre l’argomento dobbiamo indagare un po’ come lavora un computer quando deve eseguire un programma. Vediamo di scoprirlo.<br />
<br />
<br/>Vi ricordate che per esprimere la dimensione di un array abbiamo detto che avremmo usato come unità di misura i byte? Beh, non avevamo molta scelta: il ''byte'' è l’unità di misura della memoria di un computer. Qualunque dato inseriate con qualsiasi mezzo nella memoria di un computer, questo non potrà occupare meno di un byte. Diciamo che un byte è un mattoncino di memoria, la casella più piccola che ci possa essere.<br />
<br />
Quando dichiariamo una variabile, il computer prende uno spazio di memoria e lo riserva a noi, ai nostri dati. Non è detto però che un singolo byte possa bastare a farci entrare quello che ci serve.<br />
<br />
Nel C++ quando diciamo al computer di lasciarci uno spazio di memoria, gli specifichiamo anche che cosa ci metteremo dentro, ossia il ''tipo'' di dato per cui ci servirà quello spazio di memoria.<br />
<br />
In questo modo, se gli diciamo che ci dobbiamo mettere qualcosa di voluminoso, lui si preparerà lasciandoci uno spazio composto da più celle affiancate, ossia da più ''byte''.<br />
<br />
<br/>È ora di entrare un po’ più dentro a questo argomento.<br />
<br />
Proviamo con il seguente programmino:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
int dimensione;<br />
<br />
dimensione = sizeof(int);<br />
<br />
cout << "Su questa macchina, una variabile intera è composta da "<br />
<< dimensione << " byte." << endl << endl;<br />
}</pre><br />
Non dovrebbe essere difficile intuire cosa fa, ma ora lo analizzeremo insieme. L’avete già fatto girare? Bene.<br />
<br />
A me dice che una variabile intera è composta da 4 byte, ma ad altri può aver dato un’altra risposta: dipende dal vostro computer, infatti, non è universale.<br />
<br />
<br/>Questo significa che, sul mio pc, quando scrivo:<br />
<pre>int unavariabile;</pre><br />
il compilatore mi riserva uno spazio di memoria composto da quattro celle affiancate di un byte ciascuna.<br />
<br />
Se non afferrate perché questo sia così importante, ve lo dico subito: significa che lo spazio a mia disposizione è limitato. Se ho ‘solo’ 4 byte a disposizione, nella mia variabile non potrò inserire qualsiasi valore, bensì al massimo 4.294.967.295. Il numero successivo causerebbe un errore.<br />
<br />
<br/>Capito ora perché il C++ è così pignolo? Lui ci riserva esattamente l’area di memoria che chiediamo, senza sprechi.<br />
<br />
Il perché venga un numero così strano e non uno tondo, come 4.000.000.000 o 10.000.000.000, è presto detto: il computer al suo interno non usa la base dieci, ossia quella che si rappresenta i numeri con le dieci cifre 0123456789, ma la base due. Quando converte dalla base 2 alla base 10, è raro che venga fuori un numero ‘tondo’. Ma anche questa è solo una difficoltà apparente: una volta che lo si sa e ci si è fatta l’abitudine, l’importante è solo ricordarsi che c’è un limite.<br />
<br />
Ma andiamo avanti, prima che qualcuno abbia a che ridire, giacché non sono stato molto preciso.<br />
<br />
<br/>Ho infatti paura che qualcuno dei miei lettori non abbia grande confidenza con i numeri negativi…<br />
<br />
Vedere magari li avete visti tutti: -3, -86, -6.875.273, e così via. Non sono diversi dai positivi, in effetti, se ci si abitua a riportare correttamente il segno.<br />
<br />
Già, il segno…<br />
<br />
Domandina: come fa il computer a memorizzare il segno?<br />
<br />
Risposta: in effetti lo deve memorizzare '''assieme''' al numero, nello stesso spazio di memoria.<br />
<br />
Conclusione: il mio spazio di memoria in realtà non può arrivare a contenere il numero 4.294.967.295 perché una parte di quei quattro byte dovranno servire a contenere il segno (infatti io potrei desiderare di memorizzare un numero negativo).<br />
<br />
<br/>Adesso possiamo essere un altro poco più precisi: sul mio computer una variabile intera può contenere i numeri che non sono più piccoli di -2.147.483.647 e non sono più grandi di 2.147.483.647.<br />
<br />
È comunque un bel numero, non vi pare?<br />
<br />
Immagino che vi starete domandando: «E se mi serve un numero più grande?». Beh, a tutto c’è una soluzione.<br />
<br />
Intanto, se il numero che vi serve sta tra 2.147.483.647 e 4.294.967.295, allora potete usare un trucchetto: potete dire al compilatore: «Carissimo, sappi che userò solo numeri positivi, perciò non lasciare spazio per il segno: voglio tutti i miei 4 byte interi per il numero!».<br />
<br />
Questo si può fare in modo semplice, basta scrivere ''unsigned'' prima di ''int'':<br />
<pre>unsigned int unavariabile;</pre><br />
A questo punto avrete tutti e 4 i byte per voi, pertanto potrete metterci un numero che va da 0 a 4.294.967.295 (il ché implica che, se ci mettete -1 o un altro numero negativo, il computer vi darà errore!).<br />
<br />
Oltre a questo, quei geniacci che hanno lavorato sul C++ hanno fatto davvero un buon lavoro: esistono altre due possibilità: ''long'' e ''long long''.<br />
<br />
<br/>Un ''long int'' è una variabile dove ci sono più byte che in un ''int'', ma quanti esattamente dipende sempre dal vostro computer; in un ''long long int'' ce ne sono ancora di più! Proviamo a misurare quanti:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
int dimensione;<br />
<br />
dimensione = sizeof(long long int);<br />
<br />
cout << "Su questa macchina, una variabile long long int è composta da "<br />
<< dimensione << " byte." << endl << endl;<br />
}</pre><br />
Wow! Per me sono ben 8 byte. Un bel po’ di spazio, mi sembra.<br />
<br />
Come dite? Vi sembra comunque troppo poco? Come? Al massimo ci può stare il numero 8.589.934.590?<br />
<br />
No, non è così: in 8 byte, se la variabile è dichiarata ''unsigned'', si può arrivare ad inserire il numero 18.446.744.073.709.551.615, che è più che sufficiente per la maggior parte degli scopi&nbsp;:)<br />
<br />
<br/>Adesso però devo scusarmi: vi avevo promesso che avremmo guardato il programma insieme e non l’ho fatto. Provvedo subito.<br />
<br />
L’unica riga oscura, però, è questa:<br />
<pre>dimensione = sizeof(long long int);</pre><br />
Beh, sizeof l’abbiamo già incontrata quando dovevamo calcolare la dimensione totale di un array.<br />
<br />
Qui stiamo facendo la stessa cosa: sizeof ci dice (''ritorna'') quanti byte occupa un oggetto che può stare in memoria. Non sempre è in grado di dare una risposta, ma di solito sì e su cose semplici come gli ''int'' e i ''long'' è garantito che ce la fa.<br />
<br />
Il resto dovrebbe essere chiaro.<br />
<br />
<br/>Bene, ora che abbiamo introdotto i ''long'' abbiamo tutti gli strumenti per procedere verso i ''references''.<br />
<br />
<br />
<br />
==== Scusi, sa mica l’indirizzo di…? ====<br />
<br />
Sappiamo che una variabile è una cella di memoria che è contraddistinta da un nome e che contiene i dati che scegliamo noi di metterci. Questo ci dovrebbe far sospettare che esistano altre celle di memoria, che magari non hanno nome, e che contengono dati che il computer sceglie di metterci senza stare a sentire la nostra opinione. Ebbene, è proprio così. Consideriamo il seguente blocco di codice:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
void miafunzione(int mioargomento);<br />
<br />
int globale;<br />
<br />
int main()<br />
{<br />
globale = 1;<br />
int var_di_main = 1;<br />
var_di_main++; // adesso var_di_main == 2<br />
<br />
cout << "globale = " << globale << endl;<br />
cout << "var_di_main = " << var_di_main << endl;<br />
<br />
miafunzione(3);<br />
}<br />
<br />
void miafunzione(int mioargomento) // mioargomento == 3<br />
{<br />
int var_di_miafunz = mioargomento; // var_di_miafunz == 3<br />
var_di_miafunz++; // adesso var_di_miafunz == 4<br />
<br />
cout << "mioargomento = " << mioargomento << endl;<br />
cout << "var_di_miafunz = " << var_di_miafunz << endl << endl;<br />
}</pre><br />
Ciò che questo programma fa è immediatamente evidente e l’output che si ottiene è del tutto prevedibile. Comunque provate: copiatelo in main.cpp di Prove, compilatelo e fatelo girare per confermarvi che avete visto giusto.<br />
<br />
In questo programma vengono immessi alcuni dati in delle variabili, che abbiamo scelto intere per non complicarci la vita, e poi vengono presentati a schermo. Questo, possiamo dire, è il modo ‘normale’ di usare delle variabili, indicando al compilatore la loro etichetta (detta anche nome della variabile).<br />
<br />
<br/>Ma esiste un altro modo; proviamo a modificare il programma così:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
void miafunzione(int mioargomento);<br />
<br />
int globale;<br />
<br />
int main()<br />
{<br />
globale = 1;<br />
int var_di_main = 1;<br />
var_di_main++; // adesso var_di_main == 2<br />
<br />
cout << "Indirizzo di globale = " << (unsigned int) (&globale) << endl;<br />
cout << "Indirizzo di var_di_main = " << (unsigned int) (&var_di_main) << endl;<br />
<br />
miafunzione(3);<br />
}<br />
<br />
void miafunzione(int mioargomento) // mioargomento == 3<br />
{<br />
int var_di_miafunz = mioargomento; // var_di_miafunz == 4<br />
var_di_miafunz++; // adesso var_di_miafunz == 5<br />
<br />
cout << "Indirizzo di mioargomento = " << (unsigned int) (&mioargomento) << endl;<br />
cout << "Indirizzo di var_di_miafunz = "<br />
<< (unsigned int) (&var_di_miafunz) << endl << endl;<br />
}</pre><br />
ATTENZIONE!! Questo programma potrebbe darvi errore quando provate a eseguirlo.<br />
<br />
Il fatto è che stiamo lavorando con numeri piuttosto grandi, per cui alcuni potrebbero essere costretti a modificare le scritte (''unsigned int'') dentro le istruzioni ''cout'' in (''unsigned long int'') o, se non bastasse, a (''unsigned long long int)''. In quest’ultimo caso, dovremmo riuscire a sfangarla.<br />
<br />
<br/>Anche dopo questa modifica può darsi che il risultato che ottenete vi sembri incomprensibile. Calma e sangue freddo!&nbsp;:)<br />
<br />
Intanto vi dico cosa viene fuori a me:<br />
<br />
Indirizzo di globale = 134520884 Indirizzo di var_di_main = 3215607996 Indirizzo di mioargomento = 3215607968 Indirizzo di var_di_miafunz = 3215607948&lt;/pre&gt;<br />
<br />
Ma la cosa divertente è che, se chiudo la finestra e faccio girare il programma un’altra volta… il risultato cambia! Ecco a voi il secondo round:<br />
<br />
<br/>[[File:Qt III 01.png|Qt_III_01.png]]<br />
<br />
Domanda: cosa saranno quegli strani numerini?<br />
<br />
E cosa vorrà dire quello strano simbolo ‘&’ che abbiamo usato?<br />
<br />
<br/>Okay, saltiamoci subito dentro a piè pari, tanto è inutile rimandare.<br />
<br />
Fin qui ci siamo abituati a fare una cosa molto comoda: quando avevamo bisogno di una variabile dicevamo al compilatore: «Ehi, metti un’etichetta a questo spazio di memoria e tienilo libero per me!». Da quel momento in poi eravamo in grado di accedere a quello spazio di memoria semplicemente usando quell’etichetta (il nome della variabile).<br />
<br />
Questo però non è il sistema che il computer usa. Il computer non usa le etichette, bensì numera in modo progressivo tutte le celle di memoria, ossia assegna ad ognuno di loro un numerino identificativo, che è univoco. Quando noi gli chiediamo di accedere allo spazio di memoria con l’etichetta ‘miavariabile’, lui va a consultare i suoi appunti e verifica in che punto si trova quella cella di memoria, ossia qual è il suo numero progressivo, e solo a quel punto riesce a recuperare i nostri dati.<br />
<br />
<br/>Vi ricordate l’esempio del postino che metteva le buste nelle cassette della posta a seconda del nome che c’era scritto sulla busta? Immaginate il postino che entra in un condomino dove c’è una bella fila di cassette della posta, su alcune delle quali però le targhette con i nomi sono tutte sbiadite. Il povero postino ha in mano una busta dove compare un nome che non è fra quelli leggibili, per cui non sa cosa fare.<br />
<br />
Per fortuna in quel momento entra un condomino, così il postino può chiedere a lui se sa qual è la cassetta della posta giusta. Il condomino risponde: «Ma certo! È la numero 5 partendo da sinistra.»<br />
<br />
A quel punto la busta può essere inserita nella giusta cassetta della posta giacché è indifferente riconoscerla in base alla targhetta che c’è scritta sopra o in base al numero progressivo nella serie.<br />
<br />
<br/>La memoria del computer funziona alla stessa maniera: quando il computer carica il programma in memoria, gli assegna uno spazio riservato a cui gli altri programmi in funzione non possono accedere (come lui non potrà accedere a quello degli altri); all’interno di questo grossa scatola di memoria verranno via via inserite le istruzioni che vengono lette dai vari blocchi di codice dividendole in tante scatoline più piccole, tutto in maniera molto ordinata; all’interno di queste scatoline ne vengono create altre più piccole che rappresentano le nostra variabili.<br />
<br />
Ogni cella di memoria ha un suo numero e il computer le riconosce in base a quel numero.<br />
<br />
<br/>L’esempio del postino calza a pennello perché in informatica quel numero viene chiamato ''indirizzo''. Ogni cella di memoria ha quindi un indirizzo; una variabile è una cella di memoria con un nome; ogni variabile ha quindi un nome '''E''' un indirizzo.<br />
<br />
Per noi esseri umani è molto comodo riferirsi a una variabile tramite il suo nome giacché i numeri si ricordano male; per il computer è l’esatto opposto: lui preferisce il numero progressivo, cioè l’''indirizzo''.<br />
<br />
Se ci punge vaghezza di scoprire qual è l’indirizzo di memoria di una variabile, possiamo recuperarlo tramite il simbolo ‘&’. Questo simbolo, usato '''alla sinistra''' di un nome di variabile (vale a dire così: &miavariabile), significa “indirizzo di”. Quando il compilatore legge quel simbolo prima del nome di variabile, capisce che quello che stiamo cercando '''non''' è il dato contenuto nella variabile, ma l’'''indirizzo''' della variabile.<br />
<br />
<br/>In altre parole:<br />
<pre>int miavariabile = 1;</pre><br />
crea una variabile e vi inserisce il valore “1”.<br />
<br />
Questa variabile, oltre al nome, ha anche un indirizzo, di solito un numero molto grande perché in un computer ci sono una sacco di celle di memoria; però in questo momento di quell’indirizzo non ce ne curiamo.<br />
<pre>cout << miavariabile;</pre><br />
farà comparire a schermo la scritta “1”. Anche qui non siamo interessati all’indirizzo della variabile.<br />
<br />
D’un tratto, però, ci viene voglia di scoprirlo:<br />
<pre>cout << (unsigned long int) (&miavariabile);</pre><br />
Quest’istruzione farà comparire a schermo l’indirizzo della variabile ‘miavariabile’ dove è contenuto il valore “1”. La variabile non subisce alcuna modificazione, soltanto noi abbiamo chiesto al compilatore un’informazione diversa: non il valore contenuto nella cella di memoria identificata dall’etichetta ‘miavariabile’, ma l’indirizzo della cella di memoria che abbiamo chiamato ‘miavariabile’.<br />
<br />
<br/>Alcune precisazioni.<br />
<br />
La parola magica ''cout'' cerca di capire di che tipo è il dato che stiamo cercando di mandare a schermo. Infatti se non riuscisse a capirlo non saprebbe come accontentarci. Pensate a quanto possa essere diverso rappresentare a schermo un semplice ‘1’ oppure una ''string'' come: “Non sapevo come mettere in crisi cout e perciò, dopo lungo meditare, ho deciso di inviargli questa scritta davvero lunga”.<br />
<br />
Di solito se la cava egregiamente perché il compilatore è in grado di avvisarla: «Ehi, quello che ti sta arrivando è chiuso tra virgolette, perciò è facile che sia una ''string''!»; oppure: «La variabile che ti è stata passata è stata dichiarata ''int'', perciò dovresti prepararti a rappresentare un valore intero.» E così via, un sacco di buoni consigli.<br />
<br />
Quando però gli passiamo un indirizzo di variabile, il compilatore non ha indizi da passare a ''cout'' perché l’unica cosa che sa è che si tratta di un bel numerone grande e nient’altro. ''cout'', a sua volta, non sapendo cosa vogliamo noi, nel dubbio prova a rappresentarlo come un ''int'', operazione che non sempre dà buoni frutti perché un ''int'' potrebbe non essere sufficiente per gestire un numero così grosso.<br />
<br />
<br/>Per evitare tutte queste complicazioni sia al compilatore che a ''cout'' possiamo specificare '''quale tipo''' di dato stiamo inviando, gesto che il compilatore del C++ gradisce sempre moltissimo.<br />
<br />
Ecco il significato di quell’istruzione fra parentesi:<br />
<pre>(unsigned long int)</pre><br />
In pratica stiamo avvisando cout in questi termini: «Voglio che tu gestisca il dato che ti arriva come se fosse un numero intero lungo positivo.»<br />
<br />
Le parentesi sono necessarie solo perché si tratta di più parole: senza le parentesi ''cout'' non sarebbe stato in grado di capire dove iniziava e dove finiva la nostra istruzione, invece con le parentesi può interpretare correttamente la parte ''unsigned long int'' come “informazione su come devo considerare il dato che segue” e la parte ''&miavariabile'' come “ecco il dato da rappresentare!”.<br />
<br />
<br />
<br />
==== E poi distrugge tutto ====<br />
<br />
È più chiaro ora perché a ogni riavvio del programma i numeri che vengono inviati a schermo sono diversi? In modo molto semplice, quando il programma finisce (→ ''termina''), il computer lo cancella dalla memoria, rendendola libera per altri programmi che ne avessero bisogno.<br />
<br />
Nel momento in cui lo fate partire un’altra volta, il computer gli assegna di nuovo uno spazio di memoria, ma non è assolutamente detto che sia lo stesso – anzi! Quasi mai sarà identico.<br />
<br />
Pertanto le celle di memoria a disposizione del computer avranno indirizzi diversi.<br />
<br />
<br/>Però possiamo farci una prima, banale idea di come il compilatore organizza la memoria a disposizione.<br />
<br />
Prendiamo come esempio il due ‘round’ che ho riportato poco sopra.<br />
<br />
Se diamo un’occhiata ai numeri, possiamo notare come le variabili locali siano un po’ tutte piazzate nella stessa area; infatti gli indirizzi divergono poco fra di loro. Quelle che appartengono alla stessa funzione sono anche un po’ più vicine fra di loro di quella dichiarata in un’altra funzione (quanto a ‘mioargomento’, abbiamo già visto come non ci sia nessuna differenza fra una variabile locale dichiarata dopo il segno di aperta graffa e una dichiarata fra parentesi tonda se non che quest’ultima si chiama ''parametro'' e riceve il valore spedito alla funzione, detto ''argomento'').<br />
<br />
La variabile globale si trova invece molto distante da tutte le altre.<br />
<br />
<br/>Pensiamoci un po’: che fine fanno le variabili quando una funzione è finita e si torna nella funzione chiamante? Beh, se non ci avete ancora pensato, adesso dovreste essere in grado di intuire la risposta: la memoria non è infinita, pertanto il compilatore non si può permettere di sprecarla, perciò, una volta terminata l’esecuzione di una funzione, tutta la memoria che era da lei occupata viene cancellata, comprese le variabili, e ritorna disponibile per altre funzioni.<br />
<br />
In altre parole, i dati contenuti nelle variabili locali vengono persi appena si esce dalla funzione.<br />
<br />
<br/>Attenzione! Questo non accade quando si lascia una funzione per saltare dentro un’altra, perché la funzione da cui stiamo partendo non si è ancora conclusa. Però succede tutte le volte che il compilatore incontra un segno di parentesi graffa chiusa ‘}’.<br />
<br />
Quando trova il simbolo di graffa chiusa, il compilatore parte dal presupposto che quel blocco di codice non serva più, pertanto lo distrugge, recuperando spazio per caricare in memoria le prossime istruzioni che deve eseguire.<br />
<br />
SE prima del segno di graffa chiusa ha incontrato un’istruzione ''return'', allora, state bene attenti, FA UNA COPIA del valore che è indicato dopo la parola ''return'' in un altro spazio di memoria che sa lui, al quale noi non possiamo accedere e nemmeno sapere quale sia l’indirizzo, e, '''dopo aver distrutto il blocco di codice che è terminato''', lo consegna alla funzione chiamante.<br />
<br />
Ciò che segue l'istruzione ''return'' è pertanto l’unica cosa che si salva, e si salva perché viene copiata in una zona di memoria che il compilatore gestisce per sé, ma il blocco originario, comprese tutte le variabili che erano state dichiarate lì, viene distrutto senza possibilità di recupero.<br />
<br />
<br/>Questo ci dovrebbe dare un’idea di come il compilatore divida la memoria in blocchi logici, mettendo da una parte le cose che si suppone abbiano un ciclo di ‘vita’ più lungo (le variabili globali, che saranno cancellate solo alla fine del programma), e usando un’area separata per le cose che ‘moriranno’ presto (le variabili locali, create ex novo ad ogni chiamata di funzione e distrutte ad ogni conclusione di funzione).<br />
<br />
<br/>Un po’ troppa teoria? Vi capisco, ma prima o poi l’argomento andava affrontato. È perché ora arrivano…<br />
<br />
<br />
<br />
=== I references ===<br />
<br />
==== Che cosa sono ====<br />
<br />
Eccole qua, quelle brutte bestiacce. Pensavano di farci paura, ma ora che abbiamo scoperto i loro segreti siamo perfettamente in grado di domarle.<br />
<br />
<br/>Vi confesso che, essendo incappato nel C++ dopo aver battuto il naso contro il C, dove i ''references'' non c’erano, il primo pensiero che mi è sorto è stato: «E che ci faccio con questa roba? Non li userò mai.»<br />
<br />
Infatti nel C ci sono i puntatori (anche nel C++, che li ha ereditati da lui) che possono fare tutto quello che fanno i ''references'' e anche di più, per cui mi sembrava che si trattasse solo di una brutta copia di quelli. Qualcosa di superfluo, quindi, di ridondante.<br />
<br />
Mi ci è voluto un bel po’ di tempo per capire che, sì, se siamo maligni possiamo definire i ''references'' come dei puntatori semplificati, ma la loro semplicità di utilizzo li rende molto più maneggevoli dei puntatori in un sacco di casi, ossia in tutti quelli in cui le ‘funzioni avanzate’ dei puntatori (leggi: l’aritmetica dei puntatori) non è richiesta.<br />
<br />
Oggi mi sono convinto che il percorso di apprendimento tradizionale (prima i puntatori, che sono più difficile, e poi i ''references'', che sono più facili) è assurdo! L’uso dei ''references'' rende i puntatori molto meno ostici da capire.<br />
<br />
<br/>Ma cosa sono infine questi ''references''?<br />
<br />
In realtà qualcosa di molto semplice. Capire cosa sono è immediato. Capire perché sono così comodi richiede un po’ più di tempo.<br />
<br />
Mettiamo che io abbia una variabile qualsiasi, cui possiamo dare il classico nome di ‘miavariabile’:<br />
<pre>int miavariabile;</pre><br />
Il tipo int è il più semplice da usare, perciò quando si deve introdurre un nuovo argomento di solito si sceglie quello, ma il discorso che stiamo per fare vale per qualsiasi tipo di variabile.<br />
<br />
Alla mia comunissima variabile posso assegnare un valore qualsiasi, diciamo 10:<br />
<pre>miavariabile = 10;</pre><br />
Abbiamo visto che di questa variabile possiamo ottenere l’indirizzo. Questo indirizzo è solo un numero, per quanto grande; perciò può stare dentro un’altra variabile che, per coerenza, posso chiamare ‘indirizzo’ (ma anche ‘Pluto’, se mi piacesse farlo). Proviamoci:<br />
<pre>unsigned long int indirizzo;<br />
indirizzo = (unsigned long int) (&miavariabile);</pre><br />
Anche in questo caso mi devo garantire che l’indirizzo sia correttamente interpretato come unsigned long int, altrimenti il compilatore mi darebbe un messaggio di errore (per ora non possiamo stare ad analizzare il perché). A questo punto potrei divertirmi a controllare il contenuto delle due variabili:<br />
<pre>cout << "miavariabile = " << miavariabile << endl;<br />
cout << "indirizzo = " << indirizzo << endl << endl;</pre><br />
Nota: come vedete stavolta non abbiamo dovuto avvertire cout scrivendo (unsigned long int) prima di indirizzo, perché il compilatore sa già che ‘indirizzo’ è di tipo unsigned long int, perciò può avvisare cout senza bisogno del nostro aiuto.<br />
<br />
Il risultato è quello che penso tutti si aspettassero:<br />
<br />
<br/>[[File:Qt III 02.png|Qt_III_02.png]]<br />
<br />
Il valore di ‘indirizzo’ sarà diverso computer per computer e anche sullo stesso computer potrebbe cambiare tutte le volte che si fa girare il programma.<br />
<br />
<br/>Per i pigroni cui ha fatto fatica di scrivere il codice fin qui, eccolo:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
int miavariabile;<br />
miavariabile = 10;<br />
<br />
unsigned long int indirizzo;<br />
indirizzo = (unsigned long int) (&miavariabile);<br />
<br />
cout << "miavariabile = " << miavariabile << endl;<br />
cout << "indirizzo = " << indirizzo << endl << endl;<br />
}</pre><br />
Però badate che d’ora innanzi non è garantito che vi copi tutti i pezzi di codice, anche quelli di poche righe come questo, nel tutorial: dovete abituarvi a scrivere le istruzioni dentro l’ambiente di programmazione.<br />
<br />
A questo punto sembra che non abbiamo niente di particolarmente utile: abbiamo una variabile che contiene il valore 10 e un’altra che contiene un numero grande che, per l’appunto, corrisponde all’indirizzo della prima variabile. Ma ci servirà a qualcosa?<br />
<br />
Ad esempio, cosa succederebbe se decidessimo di cambiare il numero contenuto in ‘indirizzo’? Il fatto che corrisponda all’indirizzo di un’altra variabile avrà qualche conseguenza? Proviamo:<br />
<pre>indirizzo = 13; // un numero a caso, dedicato ai superstiziosi&nbsp;:)</pre><br />
Se riscriviamo<br />
<pre>cout << "miavariabile = " << miavariabile << endl;<br />
cout << "indirizzo = " << indirizzo << endl << endl;</pre><br />
otteniamo proprio il risultato che ci aspettavamo:<br />
<br />
<br/>[[File:Qt III 03.png|Qt_III_03.png]]<br />
<br />
<br/>Perché non avrebbe dovuto andare così? Le due variabili sono due celle di memoria distinte e il valore che è contenuto in una non influenza quello che è contenuto nell’altra. Non ha nessuna importanza che possano avere entrambe lo stesso valore o che il valore di una sia la metà di quello dell’altra o un terzo o la radice quadrata, oppure per l’appunto il suo indirizzo: non c’è alcun rapporto fra le due. Punto e chiuso.<br />
<br />
<br/>È tutto vero. Ma solo perché abbiamo usato il simbolo ‘&’ senza creare un ''reference''&nbsp;:)<br />
<br />
Proviamo a scrivere le stesse cose in un’altra maniera:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
int miavariabile = 10;<br />
int& indirizzo = miavariabile;<br />
<br />
cout << "miavariabile = " << miavariabile << endl;<br />
cout << "indirizzo = " << indirizzo << endl << endl; <br />
}</pre><br />
Avete visto dov’è finito il simbolo ‘&’? Provate a far girare questo programma e ditemi se dà il risultato che vi aspettavate.<br />
<br />
<br/>[[File:Qt III 04.png|Qt_III_04.png]]<br />
<br />
<br/>Sorpresi? Spero che lo siate.<br />
<br />
Quello che abbiamo ottenuto spostando il simbolo ‘&’ dopo l’indicatore del tipo di variabile (''int'') è stata la creazione di un nuovo tipo di variabile: la variabile riferimento, ossia un ''reference''.<br />
<br />
Un ''reference'' è una normale variabile, ma con una piccola differenza: quando la si crea, l’unica sintassi lecita per dichiararla è facendola seguire da un segno di uguale e dal nome di un’altra variabile già dichiarata in precedenza.<br />
<br />
In pratica, NON si può scrivere:<br />
<pre>int& indirizzo;</pre><br />
È semplicemente proibito, non si può fare. Si può fare solo:<br />
<pre>int& indirizzo = nome di un’altra variabile già dichiarata.</pre><br />
A quel punto il reference diventa un nome sostitutivo per l’altra variabile. Ossia, da quel momento in poi potremo far riferimento allo spazio di memoria contrassegnato con l’etichetta ‘miavariabile’ anche con il nome ‘indirizzo’. In pratica, lo stesso spazio di memoria avrà due etichette e usare l’una o l’altra sarà indifferente.<br />
<br />
Vogliamo verificare?<br />
<br />
Proviamo ad aggiungere le stesse righe di prima al nuovo programma:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
int miavariabile = 10;<br />
int& indirizzo = miavariabile;<br />
<br />
cout << "miavariabile = " << miavariabile << endl;<br />
cout << "indirizzo = " << indirizzo << endl << endl;<br />
<br />
indirizzo = 13; // un numero a caso, dedicato ai superstiziosi&nbsp;:)<br />
<br />
cout << "miavariabile = " << miavariabile << endl;<br />
cout << "indirizzo = " << indirizzo << endl << endl;<br />
}</pre><br />
Qual è il nuovo risultato che avete ottenuto?<br />
<br />
<br/>[[File:Qt III 05.png|Qt_III_05.png]]<br />
<br />
<br/>Se la cosa vi lascia perplessi, ricordatevi quello che vi ho detto: capire cos’è un ''reference'' è semplice; intuire '''a cosa serve''' è un po’ meno immediato. Però ci arriveremo molto presto, adesso non fatevi bloccare dall’idea che a prima vista sembri una cosa del tutto inutile.<br />
<br />
Un ''reference'' non è altro che questo: un secondo nome per '''la stessa variabile'''.<br />
<br />
<br/>Riuscite a intuire almeno perché sia stato scelto proprio il simbolo ‘&’ per creare i ''reference''? Beh, a dir la verità questo nessuno lo sa eccetto il signor Stroustrup&nbsp;:) Però possiamo specularci un po’ sopra.<br />
<br />
Si è detto che il computer usa gli indirizzi delle variabili per accedere ai valori contenuti, e non i nomi: quelli sono una comodità per noi esseri umani. Bene, cosa ci potrebbe essere di più semplice per un compilatore che sentirsi chiedere: «Ehi, attaccami questa etichetta a questo indirizzo di memoria»?<br />
<br />
Per il compilatore, che lì ci sia già un’etichetta non ha la minima importanza: lui si limita a eseguire gli ordini.<br />
<br />
<br/>Adesso vediamo perché vogliamo dare più nomi alle stesse variabili.<br />
<br />
<br />
<br />
==== Ma a che diavolo servono? ====<br />
<br />
Per dare una prima idea dell’utilità dei ''reference'', torniamo al nostro gioco dei fiammiferi e apportiamoci qualche piccola modifica.<br />
<br />
Per ora ci limiteremo a cambiare il nome della variabile ‘fiammiferi’ che si trova nelle due funzioni ''mossaCane()'' e ''mossaAnatra()''. Abbiamo già visto che non sarebbe necessario: il compilatore non fa alcuna confusione fra queste variabili; però ora stiamo per mettere in luce un nuovo aspetto e mi voglio garantire che nessuno faccia confusione con i nomi.<br />
<br />
Perciò ‘fiammiferi’ dentro ''mossaCane()'' diventerà ‘fiammi_cane’ e fiammiferi dentro ''mossaAnatra()'' diventerà ‘fiammi_anatra’. Tanto per capirci, viene così:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
void spiegazioni();<br />
int mossaCane(int fiammi_cane);<br />
int mossaAnatra(int fiammi_anatra);<br />
<br />
int main()<br />
{<br />
spiegazioni();<br />
int fiammiferi = 21;<br />
<br />
do {<br />
fiammiferi = mossaCane(fiammiferi);<br />
fiammiferi = mossaAnatra(fiammiferi);<br />
} while ( 1 < fiammiferi );<br />
<br />
cout << endl << "* * * * * * * * * * * * * * * * * * * * * * * * * * *"<br />
<< endl;<br />
cout << "Mi spiace, sei rimasto con l'ultimo"<br />
" fiammifero..." << endl;<br />
cout << "Ho vinto io." << endl;<br />
cout << "* * * * * * * * * * * * * * * * * * * * * * * * * * *"<br />
<< endl << endl;<br />
<br />
return 0;<br />
}<br />
<br />
void spiegazioni()<br />
{<br />
cout << "Ci sono 21 fiammiferi." << endl;<br />
cout << "Ne possiamo prendere da 1 a 4 per volta." << endl;<br />
cout << "Chi rimane con l'ultimo ha perso." << endl;<br />
cout << endl << "Hai la prima mossa." << endl << endl;<br />
}<br />
<br />
int mossaCane(int fiammi_cane)<br />
{<br />
int presa = 0;<br />
<br />
while ( presa < 1 || presa > 4 ){<br />
<br />
cout << "Quanti fiammiferi prendi (da 1 a 4)? " << endl;<br />
cin >> presa;<br />
<br />
if( presa < 1 || presa > 4) {<br />
cout << "Spiacente. Devi prendere almeno un fiammifero, "<br />
"ma non più di quattro..." << endl << endl;<br />
}<br />
<br />
}<br />
<br />
fiammi_cane -= presa;<br />
cout << "Hai preso " << presa << " fiammiferi." << endl;<br />
cout << "Ne rimangono " << fiammi_cane << "." << endl;<br />
<br />
return fiammi_cane;<br />
}<br />
<br />
int mossaAnatra(int fiammi_anatra)<br />
{<br />
int presa;<br />
<br />
if( 1 < fiammi_anatra ) {<br />
presa = fiammi_anatra - 1;<br />
}<br />
if( 6 < fiammi_anatra ) {<br />
presa = fiammi_anatra - 6;<br />
}<br />
if( 11 < fiammi_anatra ) {<br />
presa = fiammi_anatra - 11;<br />
}<br />
if( 16 < fiammi_anatra ) {<br />
presa = fiammi_anatra - 16;<br />
}<br />
<br />
fiammi_anatra -= presa;<br />
<br />
cout << "Io prendo " << presa << " fiammiferi." << endl;<br />
cout << "Adesso ne rimangono " << fiammi_anatra << "." << endl<br />
<< endl;<br />
<br />
return fiammi_anatra;<br />
}</pre><br />
Per ora è identico a prima, a parte la variazione sui nomi.<br />
<br />
Adesso andiamo a inserirci i nostri ''references'' (commento le righe modificate):<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
void spiegazioni();<br />
void mossaCane(int& fiammi_cane); // modificata<br />
void mossaAnatra(int& fiammi_anatra); // modificata<br />
<br />
int main()<br />
{<br />
spiegazioni();<br />
int fiammiferi = 21;<br />
<br />
do {<br />
mossaCane(fiammiferi); // modificata<br />
mossaAnatra(fiammiferi); // modificata<br />
} while ( 1 < fiammiferi );<br />
<br />
cout << endl << "* * * * * * * * * * * * * * * * * * * * * * * * * * *"<br />
<< endl;<br />
cout << "Mi spiace, sei rimasto con l'ultimo"<br />
" fiammifero..." << endl;<br />
cout << "Ho vinto io." << endl;<br />
cout << "* * * * * * * * * * * * * * * * * * * * * * * * * * *"<br />
<< endl << endl;<br />
<br />
return 0;<br />
}<br />
<br />
void spiegazioni()<br />
{<br />
cout << "Ci sono 21 fiammiferi." << endl;<br />
cout << "Ne possiamo prendere da 1 a 4 per volta." << endl;<br />
cout << "Chi rimane con l'ultimo ha perso." << endl;<br />
cout << endl << "Hai la prima mossa." << endl << endl;<br />
}<br />
<br />
void mossaCane(int& fiammi_cane) // modificata<br />
{<br />
int presa = 0;<br />
<br />
while ( presa < 1 || presa > 4 ){<br />
<br />
cout << "Quanti fiammiferi prendi (da 1 a 4)? " << endl;<br />
cin >> presa;<br />
<br />
if( presa < 1 || presa > 4) {<br />
cout << "Spiacente. Devi prendere almeno un fiammifero, "<br />
"ma non più di quattro..." << endl << endl;<br />
}<br />
<br />
}<br />
<br />
fiammi_cane -= presa;<br />
cout << "Hai preso " << presa << " fiammiferi." << endl;<br />
cout << "Ne rimangono " << fiammi_cane << "." << endl;<br />
// modificata<br />
}<br />
<br />
void mossaAnatra(int& fiammi_anatra) // modificata<br />
{<br />
int presa;<br />
<br />
if( 1 < fiammi_anatra ) {<br />
presa = fiammi_anatra - 1;<br />
}<br />
if( 6 < fiammi_anatra ) {<br />
presa = fiammi_anatra - 6;<br />
}<br />
if( 11 < fiammi_anatra ) {<br />
presa = fiammi_anatra - 11;<br />
}<br />
if( 16 < fiammi_anatra ) {<br />
presa = fiammi_anatra - 16;<br />
}<br />
<br />
fiammi_anatra -= presa;<br />
<br />
cout << "Io prendo " << presa << " fiammiferi." << endl;<br />
cout << "Adesso ne rimangono " << fiammi_anatra << "." << endl<br />
<< endl;<br />
// modificata<br />
}</pre><br />
Riuscite a vedere tutte le differenze? Mi rendo conto che non è semplice, perciò guardiamole insieme.<br />
<br />
Partendo dall’alto:<br />
<br />
<br />
<br />
{| class="wikitable"<br />
|-<br />
! <center>n.</center><br />
! <center>precedente</center><br />
! <center>attuale</center><br />
|-<br />
| 1<br />
| int mossaCane(int fiammi_cane);<br />
| void mossaCane(int& fiammi_cane);<br />
|-<br />
| 2<br />
| int mossaAnatra(int fiammi_anatra);<br />
| void mossaAnatra(int& fiammi_anatra);<br />
|-<br />
| 3<br />
| fiammiferi = mossaCane(fiammiferi);<br />
| mossaCane(fiammiferi);<br />
|-<br />
| 4<br />
| fiammiferi = mossaAnatra(fiammiferi);<br />
| mossaAnatra(fiammiferi);<br />
|-<br />
| 5<br />
| int mossaCane(int fiammi_cane)<br />
| void mossaCane(int& fiammi_cane)<br />
|-<br />
| 6<br />
| return fiammi_cane;<br />
| -<br />
|-<br />
| 7<br />
| int mossaAnatra(int fiammi_anatra)<br />
| void mossaAnatra(int& fiammi_anatra)<br />
|-<br />
| 8<br />
| return fiammi_anatra;<br />
| -<br />
|}<br />
<br />
<br/>Prima di guardarle una per una cerchiamo di capire complessivamente cos’è cambiato.<br />
<br />
<br/>Nel momento in cui definiamo ‘fiammi_cane’ e ‘fiammi_anatra’ come due ''references'' invece che due variabili ‘ordinarie’, queste diventano degli ''alias'', ossia dei nuovi nomi, della variabile ‘fiammiferi’. Ciò significa che tutto ciò che viene fatto ai valori di ‘fiammi_cane’ e ‘fiammi_anatra’ si riflette seduta stante sul valore di ‘fiammiferi’. Anzi! Direi proprio che mi sono espresso male: ciò che viene fatto a ‘fiammi_cane’ e ‘fiammi_anatra’ viene fatto a ‘fiammiferi’ perché è sempre la stessa variabile, solo che ora ha tre nomi.<br />
<br />
Compreso questo, si capisce anche che non c’è più bisogno che le funzioni ''mossaCane()'' e ''mossaAnatra()'' restituiscano il valore di ‘fiammi_cane’ e ‘fiammi_anatra’ perché ‘fiammiferi’ È GIÀ STATA MODIFICATA prima ancora che il compilatore torni dentro ''main()''. ‘fiammiferi’ viene modificata nelle altre due funzioni tramite i suoi nuovi nome, rispettivamente ‘fiammi_cane’ e ‘fiammi_anatra’.<br />
<br />
<br/>Se vi sembra che questo contraddica quanto detto sopra, cioè che non si può dichiarare un ''reference'' senza connetterlo subito a una variabile esistente, direi che formalmente avete ragione, ma nella pratica la regola viene rispettata.<br />
<br />
Prendiamo il caso di ‘fiammi_cane’ (ma lo stesso ragionamento si applica a ‘fiammi_anatra’). Si tratta di una normale variabile che però è anche un ''reference'' nonché il ''parametro'' di una funzione. Quando il flusso di esecuzione del programma arriva sulla sua dichiarazione, il compilatore la crea e immediatamente la connette alla variabile di cui sta trasportando il valore – esattamente ciò che si fa con i ''references''.<br />
<br />
<br/>Adesso, se permettete, ridico lo stesso concetto espresso poco sopra usando termini più tecnici: il vantaggio dell’usare un ''reference'' come ''parametro'' di una funzione consiste nell’includere nello ''spazio di visibilità'' della funzione una variabile che ne era esclusa, ma usando per essa un nuovo nome.<br />
<br />
All’uscita della funzione, il nuovo nome andrà distrutto, ma la variabile in sé no, perché è ancora visibile dalla funzione chiamante.<br />
<br />
<br/>Adesso diamo un’occhiata alle modifiche al codice.<br />
<br />
Le modifiche n. 1 e n. 2 ricalcano la 5 e la 7: le nuove funzioni non hanno più bisogno di restituire valori a ''main()'', perciò non devono più essere dichiarate ''int mossa…()'', bensì ''void'' (= sono una funzione che non restituisce alcun valore).<br />
<br />
Inoltre ora i rispettivi parametri non sono più ‘normali’ variabili, bensì ''references'', perciò saranno accompagnati dal simbolo ‘&’.<br />
<br />
<br/>Le modifiche 3 e 4 sono inevitabili, visto che le funzioni ''mossaCane()'' e ''mossaAnatra()'' non restituiscono più alcun valore. Inoltre, ‘fiammiferi’ viene già modificata all’interno di quelle due funzioni, perciò…<br />
<br />
<br/>Le modifiche 6 e 8 rappresentano il ‘vantaggio’ che abbiamo ottenuto dall’uso dei ''refrences'', ossia la possibilità di non stare a restituire alcun valore.<br />
<br />
<br/>Quel che abbiamo visto è solo un assaggio dei ''references'', ovviamente. La comodità di poter accedere a una variabile dall’esterno dello spazio di visibilità in cui è nata va molto oltre al fatto che non è più necessario rimandare indietro copia del valore tramite ''return'', però per ora accontentiamoci di aver capito cosa sono.<br />
<br />
<br/>Domanda.<br />
<br />
Secondo voi, a questo punto sarà possibile tornare a chiamare le variabili ‘fiammi_cane’ e ‘fiammi_anatra’ con il vecchio nome di ‘fiammiferi’? Oppure, trattandosi di ''references'', ossia ''alias'' della stessa variabile, il compilatore corre il rischio di fare confusione?<br />
<br />
Datevi la vostra risposta dopodiché provate. Stavolta non vi darò la soluzione perché siete più che in grado di risolvervi il problema da soli.<br />
<br />
<br/>Adesso non ci resta che, nell’ordine, vedere cosa ne pensa il JavaScript dei ''references'', ribadire il concetto chiave che abbiamo visto oggi, dare un’occhiata a un po’ di paroloni e a un limite dei ''references'', dopodiché passare ai puntatori.<br />
<br />
E lì vedrete che il gioco si fa duro&nbsp;;-)<br />
<br />
<br />
<br />
==== Differenze fra C++ e JavaScript: i references ====<br />
<br />
Abbiamo detto che nel JavaScript i ''references'' non ci sono. Andiamo subito a vedere se possiamo essere smentiti. Il codice che segue, ad esempio, sembra proprio dimostrare l’opposto.<br />
<br />
Il file index.html:<br />
<pre><!DOCTYPE html><br />
<br />
<html lang="it"><br />
<head><br />
<meta charset="utf-8"><br />
<br />
<link rel="stylesheet" type="text/css" href="standard.css" /><br />
<script type="text/javascript" src="Riferimenti.js"></script><br />
<br />
<title>HTML</title><br />
</head><br />
<br />
<body><br />
<h1>JavaScript e i references</h1><br />
<br />
<div class="invisibile" id="principale"><br />
<p>var int_1 = 1;</p><br />
<p>var int_2 = int_1;</p><br />
<br />
<div class="stacco_1em"><br />
<p>Il valore di int_1 ora è:</p><br />
<p id="primoID">&nbsp;</p><br />
</div><br />
<div><br />
<p>Il valore di int_2 ora è:</p><br />
<p id="secondoID">&nbsp;</p><br />
</div><br />
<br />
<p class="stacco_1em">int_2 = 2;</p><br />
<div><br />
<p>Il valore di int_1 ora è:</p><br />
<p id="terzoID">&nbsp;</p><br />
</div><br />
<div><br />
<p>Il valore di int_2 ora è:</p><br />
<p id="quartoID">&nbsp;</p><br />
</div><br />
<br />
<p class="stacco_1em">Conclusione: Le due variabili non interferiscono fra di loro.</p><br />
<br />
<p class="stacco_2em">var str_1 = "Sono un testo di prova";</p><br />
<p>var str_2 = str_1;</p><br />
<br />
<div class="stacco_1em"><br />
<p>Il valore di str_1 ora è:</p><br />
<p id="quintoID">&nbsp;</p><br />
</div><br />
<div><br />
<p>Il valore di str_2 ora è:</p><br />
<p id="sestoID">&nbsp;</p><br />
</div><br />
<br />
<p class="stacco_1em">str_2 = "Nuovo testo";</p><br />
<div><br />
<p>Il valore di str_1 ora è:</p><br />
<p id="settimoID">&nbsp;</p><br />
</div><br />
<div><br />
<p>Il valore di str_2 ora è:</p><br />
<p id="ottavoID">&nbsp;</p><br />
</div><br />
<br />
<p class="stacco_1em">Conclusione: Le due variabili non interferiscono fra di loro.</p><br />
<br />
<p class="stacco_2em">var elenco_1 = {"Elemento0", "Elemento1", "Elemento2"};</p><br />
<p>var elenco_2 = elenco_1;</p><br />
<br />
<div class="stacco_1em"><br />
<p>Il valore dell'elemento 0 di elenco_1 ora è:</p><br />
<p id="nonoID">&nbsp;</p><br />
</div><br />
<div><br />
<p>Il valore dell'elemento 0 di elenco_2 ora è:</p><br />
<p id="decimoID">&nbsp;</p><br />
</div><br />
<br />
<p class="stacco_1em">elenco_2[0] = "Nuovo elemento";</p><br />
<div><br />
<p>Il valore dell'elemento 0 di elenco_1 ora è:</p><br />
<p id="undicesimoID">&nbsp;</p><br />
</div><br />
<div><br />
<p>Il valore dell'elemento 0 di elenco_1 ora è:</p><br />
<p id="dodicesimoID">&nbsp;</p><br />
</div><br />
<br />
<p class="stacco_1em">Conclusione: i due oggetti INTERFERISCONO fra di loro!</p><br />
</div><br />
<br />
<div class="stacco_1em" id="ultimo"><br />
<label>Premi il pulsante per iniziare</label><br />
<input type="button" value="Esegui codice JS" onclick="prove();" /><br />
</div><br />
</body><br />
</html></pre><br />
Il file standard.css:<br />
<pre>p {<br />
margin &nbsp;: 0.2em 0 0 0;<br />
padding &nbsp;: 0;<br />
}<br />
<br />
div div p {<br />
display &nbsp;: inline;<br />
}<br />
<br />
.stacco_1em {<br />
margin-top &nbsp;: 1em;<br />
}<br />
<br />
.stacco_2em {<br />
margin-top &nbsp;: 1em;<br />
}<br />
<br />
.invisibile{<br />
display &nbsp;: none;<br />
visibility &nbsp;: hidden;<br />
}<br />
<br />
.visibile{<br />
display &nbsp;: initial;<br />
visibility &nbsp;: visible;<br />
}</pre><br />
Il file Riferimenti.js:<br />
<pre>function prove() {<br />
var int_1 = 1;<br />
var int_2 = int_1;<br />
<br />
document.getElementById("primoID").innerHTML = int_1;<br />
document.getElementById("secondoID").innerHTML = int_2;<br />
<br />
int_2 = 2;<br />
<br />
document.getElementById("terzoID").innerHTML = int_1;<br />
document.getElementById("quartoID").innerHTML = int_2;<br />
<br />
var str_1 = "Sono un testo di prova";<br />
var str_2 = str_1;<br />
<br />
document.getElementById("quintoID").innerHTML = str_1;<br />
document.getElementById("sestoID").innerHTML = str_2;<br />
<br />
str_2 = "Nuovo testo";<br />
document.getElementById("settimoID").innerHTML = str_1;<br />
document.getElementById("ottavoID").innerHTML = str_2;<br />
<br />
var elenco_1 = ["Elemento0", "Elemento1", "Elemento2"];<br />
var elenco_2 = elenco_1;<br />
<br />
document.getElementById("nonoID").innerHTML = elenco_1[0];<br />
document.getElementById("decimoID").innerHTML = elenco_2[0];<br />
<br />
elenco_2[0] = "Nuovo elemento";<br />
<br />
document.getElementById("undicesimoID").innerHTML = elenco_1[0];<br />
document.getElementById("dodicesimoID").innerHTML = elenco_2[0];<br />
<br />
document.getElementById("principale").setAttribute("class","visibile");<br />
document.getElementById("ultimo").setAttribute("class","invisibile");<br />
}</pre><br />
Anche se mi rendo conto che è un po’ noioso, vi chiedo di analizzare il codice con calma. Dovreste essere in grado di capire tutto ciò che fa.<br />
<br />
<br/>In realtà ci limitiamo a riproporre tre volte lo stesso schema: dichiariamo due variabili dello stesso tipo; passiamo il valore della prima alla seconda; controlliamo che siano uguali; modifichiamo la seconda; controlliamo che sia cambiata solo lei.<br />
<br />
Il file HTML serve solo come lista di segnaposti dove far comparire i valori delle variabili, con in più qualche riga per fra comprendere meglio quello che succede.<br />
<br />
La parte interessante è solo il codice JavaScript. Dividiamolo in tre parti e analizziamole.<br />
<br />
<br/>'''I parte'''<br />
<br />
Dichiariamo una variabile e assegniamole un valore intero. Poi creiamo un’altra variabile e stabiliamo che deve copiare il suo valore dalla prima.<br />
<br />
In apparenza va tutto bene: quando controlliamo i due valori sono identici.<br />
<br />
Poi modifichiamo il valore della seconda impostandola su un altro numero a caso.<br />
<br />
Adesso, quando andiamo a confrontare i due valori, scopriamo che sono diversi: la prima variabile è rimasta com’era, la seconda è cambiata come noi abbiamo deciso di cambiarla.<br />
<br />
<br/>Questo è esattamente ciò che ci aspettavamo: le due variabili sono entità distinte e possono essere modificate separatamente. Ciò che capita a una non ha alcun riflesso su ciò che capita all’altra.<br />
<br />
In altre parole, il segno ‘=’ non ha creato alcun legame fra di loro: ha solo fatto in modo che il valore di una fosse COPIATO nell’altra.<br />
<br />
<br/>'''II parte'''<br />
<br />
Questa parte è identica alla prima, ma per pignoleria abbiamo voluto controllare che anche le variabili cui era stata assegnata una sequenza di caratteri (un testo) si comportassero come quelle cui era stato assegnato un numero.<br />
<br />
Anche in questo caso non si è creato alcun legame.<br />
<br />
<br/>'''III parte'''<br />
<br />
Nella terza parte non abbiamo definito due variabili, bensì due array. Nel JavaScript gli array non sono variabili, bensì ''oggetti'', anche se di un tipo particolare.<br />
<br />
Gli oggetti ci riservano una sorpresa.<br />
<br />
Anche in questo caso le prime righe sembrano riproporre lo stesso schema: il secondo oggetto assume gli stessi valori del primo (beh, noi ne controlliamo solo uno, ma fidatevi: i due oggetti sono diventati identici).<br />
<br />
La novità salta alla luce quando si modifica il valore del secondo:<br />
<pre>elenco_2[0] = "Nuovo elemento";</pre><br />
Quando andiamo a controllare i rispettivi valori, nelle due righe successive, scopriamo che non solo il secondo è cambiato, bensì anche il primo.<br />
<br />
<br/>Cos’è successo?<br />
<br />
È successo che nel caso degli oggetti l’operazione ‘=’ non significa COPIA IL VALORE, bensì ASSEGNA UN NUOVO NOME.<br />
<br />
In altre parole, mentre le variabili funzionano come nel C++, gli oggetti non possono essere copiati, bensì solo ricevere un nome in più. Essi si comportano COME SE fossero i ''references'' del C++.<br />
<br />
<br/>Anche in questo caso possiamo dire che sì, la sintassi del JavaScript è studiata per semplificare le cose e risultare molto amichevole, ma va lo stesso conosciuta prima di scriverci del codice perché i risultati possono essere inattesi.<br />
<br />
<br/>Ma come mai il JavaScript non dà la possibilità di copiare gli ''oggetti''? Perché è un’operazione molto dispendiosa. Anche nel C++ si cerca di evitarla ogni volta che è possibile.<br />
<br />
<br/>Prendiamo l’esempio di un array, che nel JavaScript è un oggetto dalla sintassi semplice e somiglia molto all’equivalente del C++. Un array consiste in una serie di valori; sarebbe come dire che è una serie di variabili. Ma quanto è lunga questa serie? Beh, non c’è un limite: un array potrebbe in via teorica contenere centinaia o addirittura migliaia di dati.<br />
<br />
Ora provate a immaginarvi il lavorone che dovrebbe fare il compilatore se, entrando in una funzione, trovasse un parametro che aspetta una copia di un array di duemila elementi? Se poi la funzione compisse un’operazione molto semplice, come una ricerca, per poi finire subito, tutta quella copia sarebbe stata fatta per essere distrutta poco dopo…<br />
<br />
Ma se poi la funzione fosse chiamata un’altra volta, tutto la copia dovrebbe essere effettuata di nuovo, e così via.<br />
<br />
Lo spreco di risorse sarebbe assurdo e l’esecuzione del programma lentissima.<br />
<br />
<br/>Se invece si passa un array per riferimento, a quel punto il compilatore deve trasportare un solo valore: l’indirizzo dell’array originario. Su quello spazio di memoria sarà attaccata una nuova etichetta e tutto funzionerà benissimo.<br />
<br />
<br/>In conclusione, affermare che nel JavaScript i ''references'' non esistono è formalmente vero nel senso che non c’è un’istruzione o un simbolo da usare che permetta di creare in modo esplicito un ''reference'', ma l’operazione di assegnazione di nuovo nome esiste ed è l’unica scelta quando si vuole passare un ''oggetto''.<br />
<br />
<br/>Anche in questo caso il C++ presenta le sue differenze: sia le variabili che gli oggetti possono essere copiati oppure può essere assegnato loro un nuovo nome. La sintassi è la medesima in entrambi i casi:<br />
<pre>int var_1 = 1;<br />
var_2 = 2;<br />
cout << "dopo 'var_2 = 2':" << endl;<br />
cout << "var_1 = " << var_1 << endl;<br />
cout << "var_2 = " << var_2 << endl;<br />
cout << "var_3 = " << var_3 << endl << endl;<br />
<br />
var_3 = 3;<br />
cout << "dopo 'var_3 = 3':" << endl;<br />
cout << "var_1 = " << var_1 << endl;<br />
cout << "var_2 = " << var_2 << endl;<br />
cout << "var_3 = " << var_3 << endl << endl;<br />
<br />
vector<int> vec_1 = {1, 2, 3, 4}; // crea un vector di 4 elementi<br />
vector<int> vec_2 = vec_1; // *copia* il primo vector nel secondo vector<br />
vector<int>& vec_3 = vec_1; // crea un reference al primo vector<br />
<br />
vec_2[0] = 100;<br />
cout << "dopo 'vec_2[0] = 100':" << endl;<br />
cout << "vec_1[0] = " << vec_1[0] << endl;<br />
cout << "vec_2[0] = " << vec_2[0] << endl;<br />
cout << "vec_3[0] = " << vec_3[0] << endl << endl;<br />
<br />
vec_3[0] = 13;<br />
cout << "dopo 'vec_3[0] = 13':" << endl;<br />
cout << "vec_1[0] = " << vec_1[0] << endl;<br />
cout << "vec_2[0] = " << vec_2[0] << endl;<br />
cout << "vec_3[0] = " << vec_3[0] << endl << endl;</pre><br />
Il codice non è completo, ma adesso siete perfettamente in grado di farlo funzionare.<br />
<br />
Ricordatevi:<br />
<br />
#dovete includere il file con il codice per i ''vector'' nelle prime righe (riguardate gli esempi passati!);<br />
#dovete aggiungere la riga ''CONFIG += c++11'' nel file Prove.pro.<br />
<br />
Provate a scrivete le poche righe mancanti di questo programma e a farlo girare. Cercate anche di prevedere cosa farà prima di guardare il risultato.<br />
<br />
<br/>Se proprio non ce la fate, qui sotto c’è la soluzione, ma '''provateci prima da soli'''. È facilissimo.<br />
<pre>#include <iostream><br />
#include <vector><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
int var_1 = 1;<br />
int var_2 = var_1; // copia il valore<br />
int& var_3 = var_1; // crea un reference<br />
<br />
var_2 = 2;<br />
cout << "dopo 'var_2 = 2':" << endl;<br />
cout << "var_1 = " << var_1 << endl;<br />
cout << "var_2 = " << var_2 << endl;<br />
cout << "var_3 = " << var_3 << endl << endl;<br />
<br />
var_3 = 3;<br />
cout << "dopo 'var_3 = 3':" << endl;<br />
cout << "var_1 = " << var_1 << endl;<br />
cout << "var_2 = " << var_2 << endl;<br />
cout << "var_3 = " << var_3 << endl << endl;<br />
<br />
vector<int> vec_1 = {1, 2, 3, 4}; // crea un vector di 4 elementi<br />
vector<int> vec_2 = vec_1; // *copia* il primo vector nel secondo vector<br />
vector<int>& vec_3 = vec_1; // crea un reference al primo vector<br />
<br />
vec_2[0] = 100;<br />
cout << "dopo 'vec_2[0] = 100':" << endl;<br />
cout << "vec_1[0] = " << vec_1[0] << endl;<br />
cout << "vec_2[0] = " << vec_2[0] << endl;<br />
cout << "vec_3[0] = " << vec_3[0] << endl << endl;<br />
<br />
vec_3[0] = 13;<br />
cout << "dopo 'vec_3[0] = 13':" << endl;<br />
cout << "vec_1[0] = " << vec_1[0] << endl;<br />
cout << "vec_2[0] = " << vec_2[0] << endl;<br />
cout << "vec_3[0] = " << vec_3[0] << endl << endl;<br />
<br />
return 0;<br />
}</pre><br />
Come vedete il C++ è pignolo, però coerente con le sue scelte. Una volta capita come funziona una sintassi, le sorprese sono poche.<br />
<br />
<br />
<br />
==== Differenze fra C++ e JavaScript: string ====<br />
<br />
Nel C++ ''string'' è un oggetto come tutti gli altri. L’unica sua particolarità è che si può usarlo anche solo dichiarando:<br />
<pre>#include <iostream></pre><br />
senza stare a scrivere:<br />
<pre>#include <string></pre><br />
Ma si tratta di una mera comodità che non differenzia string in modo particolare.<br />
<br />
Una ''string'' in C++ può essere modificata, copiata, passata ad un ''reference'' o quant’altro volete.<br />
<br />
Vediamo cosa succede invece nel JavaScript. Chiamerò il file HTML ProvaString.html e quello JavaScript ProvaString.js.<br />
<pre><!DOCTYPE html><br />
<br />
<html lang="it"><br />
<head><br />
<meta charset="utf-8"><br />
<br />
<link rel="stylesheet" type="text/css" href="standard.css" /><br />
<script type="text/javascript" src="ProvaString.js"></script><br />
<br />
<title>JavaScript e string</title><br />
</head><br />
<br />
<body><br />
<h1>JavaScript e string</h1><br />
<br />
<div class="invisibile" id="principale"><br />
<p>var str_1 = "Sono un testo di prova";</p><br />
<p>var str_2 = str_1;</p><br />
<br />
<p class="stacco_1em">str_2 = "Nuovo testo";</p><br />
<div><br />
<p>str_1 == </p><br />
<p id="ID_1">&nbsp;</p><br />
</div><br />
<div><br />
<p>str_2 == </p><br />
<p id="ID_2">&nbsp;</p><br />
</div><br />
<br />
<p class="stacco_1em">// La riga seguente modifica str_2 da "Nuovo testo" a "Vecchio testo"</p><br />
<p>str_2 = str_2.replace("Nuovo", "Vecchio");</p><br />
<div><br />
<p>str_1 == </p><br />
<p id="ID_3">&nbsp;</p><br />
</div><br />
<div><br />
<p>str_2 == </p><br />
<p id="ID_4">&nbsp;</p><br />
</div><br />
</div><br />
<br />
<div class="stacco_1em" id="ultimo"><br />
<label>Premi il pulsante per iniziare</label><br />
<input type="button" value="Esegui codice JS" onclick="prove();" /><br />
</div><br />
</body><br />
</html><br />
</pre><br />
ProvaString.js:<br />
<pre>function prove() {<br />
var str_1 = "Sono un testo di prova";<br />
var str_2 = str_1;<br />
<br />
str_2 = "Nuovo testo";<br />
document.getElementById("ID_1").innerHTML = str_1;<br />
document.getElementById("ID_2").innerHTML = str_2;<br />
<br />
// La riga seguente modifica str_2 da "Nuovo testo" a "Vecchio testo"<br />
str_2 = str_2.replace("Nuovo", "Vecchio");<br />
document.getElementById("ID_3").innerHTML = str_1;<br />
document.getElementById("ID_4").innerHTML = str_2;<br />
<br />
document.getElementById("principale").setAttribute("class","visibile");<br />
document.getElementById("ultimo").setAttribute("class","invisibile");<br />
}</pre><br />
Stavolta sono più brevi&nbsp;:-)<br />
<br />
L’unica novità è rappresentata dalla riga<br />
<pre>str_2 = str_2.replace("Nuovo", "Vecchio");</pre><br />
che però fa una cosa molto ovvia: il metodo replace() (in italiano, ‘sostituisci’) accetta ben due parametri invece che il classico uno e poi agisce così: cerca nella string il valore che gli è stato passato come primo argomento e lo sostituisce con il secondo.<br />
<br />
Ci viene da domandarci: ci sarà qualcosa di simile nel C++?<br />
<br />
Ebbene sì: anche nel C++ c’è un metodo ''replace()'' di ''string'', che però ha bisogno di… ancora più ''parametri''.<br />
<br />
<br/>Guardiamolo insieme.<br />
<br />
Se volessi sostituire “Nuovo” con “Vecchio” nella sequenza “Nuovo testo” dovrei dire a ''relace():''<br />
<br />
#partendo dalla posizione 0 (anche per ''string'' la prima posizione è la numero 0)<br />
#togli 5 caratteri (N-u-o-v-o)<br />
#e al posto loro metti “Vecchio”<br />
<br />
Quindi viene:<br />
<pre>nome_della_variabile.replace(0, 5, "Vecchio");</pre><br />
Vediamo se funziona.<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
string str_1 = "Sono un testo di prova";<br />
string str_2 = str_1; // copia il valore<br />
<br />
str_2 = "Nuovo testo";<br />
cout << "dopo 'Nuovo testo':" << endl;<br />
cout << "str_1 = " << str_1 << endl;<br />
cout << "str_2 = " << str_2 << endl << endl;<br />
<br />
str_2.replace(0, 5, "Vecchio");<br />
cout << "dopo 'str_2.replace':" << endl;<br />
cout << "str_1 = " << str_1 << endl;<br />
cout << "str_2 = " << str_2 << endl << endl;<br />
<br />
return 0;<br />
}</pre><br />
Provate a fare girare il programma. Direi che anche replace() dell’oggetto string del C++ fa il suo sporco lavoro.<br />
<br />
<br/>Vedete però una differenza nella sintassi, oltre al fatto che nel C++ abbiamo bisogno di 3 ''parametri''?<br />
<br />
In JavaScript:<br />
<pre>str_2 = str_2.replace("Nuovo", "Vecchio");</pre><br />
Nel C++:<br />
<pre>str_2.replace(0, 5, "Vecchio");</pre><br />
C’è qualcosa che vi salta all’occhio?<br />
<br />
La differenza consiste in quel ''str_2 ='' in più. In pratica, nel JavaScript dovete specificare che la ‘nuova’ stinga ''str_2'' deve diventare uguale alla ‘vecchia’ stringa ''str_2'' una volta che siano stati sostituiti dei caratteri. Torniamo indietro con la memoria: la sintassi dell’istruzione JavaScript l’abbiamo già incontrata in precedenza, quando dicevamo che per incrementare di 5 il valore di un numero intero potevamo scegliere se scrivere:<br />
<pre>var miavar = 3;<br />
miavar += 5; // miavar == 8<br />
miavar = miavar + 5; // miavar == 13</pre><br />
In quest’ultimo codice, se sostituissimo il primo ''var'' con ''int'', la stessa sintassi (derivata dal C) si potrebbe applicare pari pari al C++.<br />
<br />
Entrambe le operazioni ''trasformano'' il valore contenuto nella variabile ‘miavar’ sommandogli il numero 5.<br />
<br />
<br/>Anche in questo caso nel JavaScript è necessario ripetere che la variabile ‘str_2’ deve diventare uguale a ciò che sarà la variabile ‘str_2’ DOPO che “Nuovo” sarà stato sostituito con “Vecchio”.<br />
<br />
Nel C++ invece basta dire: agisci su ‘str_2’ sostituendo “Vecchio” ai primi 5 caratteri.<br />
<br />
<br/>Per dirla meglio: il metodo ''replace()'' di ''string'' nel JavaScript non modifica l’oggetto cui si riferisce (quello a cui è ‘attaccato’ con un punto), bensì lo usa solo come testo di partenza per '''creare una nuova string'''. Questo è dovuto al fatto che le ''string'' nel JavaScript '''non''' si possono modificare.<br />
<br />
Se modificate una ''string'', create qualcosa di nuovo che deve essere ri-passato alla variabile tramite il segno di ‘=’.<br />
<br />
<br/>Ancora non abbiamo parlato di cosa siano i ''tipi primitivi'' e cosa siano gli ''oggetti'' perché la mia idea è arrivare a scrivere il codice di un ''oggetto'' prima di spenderci tante parole teoriche sopra. Però possiamo arrivare al punto da una via secondaria.<br />
<br />
<br/>Vi ricordate che nel C++, a seconda del tipo di dato a cui è destinata una variabile, il compilatore vi fornisce (→ ''assegna'') qualche byte in più o in meno? Ok, ma ora facciamoci un’altra domanda: come diavolo fa il compilatore a sapere quanti byte lasciare liberi per la mia ''string'' se non ha idea di quanto cavolo di testo ci voglio mettere dentro? E se ci volessi mettere un libro intero?<br />
<br />
<br/>Una bella domanda in effetti, ma la risposta è ancora al di là della nostra portata. Posso dire solo questo: come un ''vector'' può contenere un numero elevatissimo di elementi così una ''string'' può contenere un numero enorme di lettere. Questo è dovuto al fatto che non sono variabili come gli ''int'' o i ''long int'', bensì ''oggetti'', ossia qualcosa che non ha una misura prefissata in anticipo. Più vi aggiungete testo, e più la ''string'' si ‘dilata’, chiedendo (e ottenendo!) dal compilatore sempre nuovi byte – almeno entro certi limiti, tra cui la memoria che il computer rende disponibile.<br />
<br />
<br/>Bene, il JavaScript vuole semplificare la vita al programmatore e consentirgli di trattare le cose come gli ''int'' come fossero oggetti; le ''string'' purtroppo cadono a metà fra questi due mondi, perché potete metterle in una ‘semplice’ variabile, ma potrebbero chiedere di gestire una quantità enorme di memoria. Per gestire le ''string'' il JavaScript deve scendere a qualche compromesso.<br />
<br />
Tutta questa teoria ci tornerà più chiara dopo che avremo fatto conoscenza con gli ''oggetti''.<br />
<br />
<br />
<br />
==== I limiti dei references ====<br />
<br />
I ''references'' funzionano molto bene, ma hanno anche qualche limite che è bene conoscere.<br />
<br />
Intanto potremmo provare a vedere se questo programma potrebbe funzionare:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
void prova(int& test);<br />
<br />
int main()<br />
{<br />
prova(5);<br />
<br />
return 0;<br />
}<br />
<br />
void prova(int& test)<br />
{<br />
cout << "Vediamo se si può fare" << endl;<br />
}</pre><br />
Se aveste poca voglia di provarlo, va bene lo stesso: infatti il compilatore si rifiuterà di portare a termine l’operazione.<br />
<br />
Come avevamo detto, un ''reference'', o variabile riferimento, o anche solo riferimento, può essere dichiarato solo passandogli una variabile già esistente.<br />
<br />
In questo caso stiamo passando un numero, che è una cosa che non ha un indirizzo di memoria con un’etichetta e a cui non si può attaccare un nome. Non è idoneo per essere passato ad un ''reference''.<br />
<br />
<br/>Questo significa che, se create una funzione che ha come parametro un ''reference'', non potrete passarle altro che una variabile. Se invece ha come come parametro una variabile ‘normale’, allora potete passarle anche un numero.<br />
<br />
<br/>Un altro aspetto dei ''references'' che è bene chiarire è che il legame che si crea con la variabile originaria è inscindibile. Ossia, una volta che si è scritto:<br />
<pre>string miavar1 = "Una frase a caso";<br />
string miavar2 = "Un’altra frase a caso";<br />
string& miavar3 = miavar;</pre><br />
Non si può più ‘tornare indietro’. In seguito si potrà scrivere:<br />
<pre>miavar3 = miavar2;</pre><br />
ma il risultato che si ottiene sarà di assegnare il valore della variabile ‘miavar2’ alla variabile ‘miavar3’, che è identico ad assegnarlo a ‘miavar’. Provare per credere:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
string miavar1 = "Una frase a caso";<br />
string miavar2 = "Un’altra frase a caso";<br />
string& miavar3 = miavar1;<br />
miavar3 = miavar2;<br />
<br />
cout << "miavar1 = " << miavar1 << endl << endl;<br />
<br />
return 0;<br />
}</pre><br />
Quindi non esiste un modo per ‘staccare’ un reference dalla variabile di cui è un alias per ‘attaccarlo’ a un’altra.<br />
<br />
<br/>I due punti appena visti sono già sufficienti a farci desiderare qualcosa di meglio, ma poniamoci un’altra domanda: sarebbe possibile ottenere l’indirizzo della variabile originaria partendo dal ''reference''? Ossia, una volta che avessi scritto:<br />
<pre>int miavar = 9; // numero a caso<br />
int& mioref = miavar; // reference a miavar</pre><br />
se scrivessi:<br />
<pre>unsigned long int ind1 = (unsigned long int) &mioref; // indirizzo di mioref</pre><br />
cosa otterrei? Lo stesso indirizzo che avrei scrivendo<br />
<pre>unsigned long int ind2= (unsigned long int) &miavar; // indirizzo di miavar</pre><br />
oppure un altro?<br />
<br />
Trovate la domanda un po’ accademica? Ci torneremo sopra, ma intanto cerchiamo la risposta.<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
int miavar = 9; // numero a caso<br />
int& mioref = miavar; // reference a miavar<br />
<br />
unsigned long int ind1 = (unsigned long int) &mioref; // indirizzo di mioref<br />
<br />
cout << "ind1 = " << ind1 << endl;<br />
<br />
unsigned long int ind2= (unsigned long int) &miavar; // indirizzo di miavar<br />
<br />
cout << "ind2 = " << ind2 << endl << endl;<br />
<br />
return 0;<br />
}</pre><br />
Ecco qui lo output:<br />
<br />
<br/>[[File:Qt III 06.png|Qt_III_06.png]]<br />
<br />
Qualunque numero vi sia venuto, quello che conta è che i valori delle due variabili siano identici.<br />
<br />
La conclusione abbastanza evidente è, se non si fosse ancora capito, che il ''reference'' non gode di vita propria: è solo un altro nome per una variabile e questo significa che noi non possiamo mai farci operazioni ‘a parte’, ossia non possiamo fare nulla su di esso che non coinvolga l’altra variabile.<br />
<br />
<br/>Pensateci un po’: non sarebbe un miglioramento avere un ''reference'' che non si debba collegare fin da subito ad una variabile? Non sarebbe bello che potesse accettare anche numeri, oltre che variabili? Non sarebbe più flessibile se si potesse ‘staccare’ da una variabile per ‘attaccarlo’ a un’altra? Non sarebbe più comodo se avesse un suo indirizzo autonomo, in modo che si potesse decidere di fare a lui qualcosa che non vogliamo che si rifletta sulla variabile?<br />
<br />
<br/>Sapete già di cosa sto parlando, vero?&nbsp;:)<br />
<br />
È ora di andare a incontrare i puntatori, dei references dopati.<br />
<br />
<br />
<br />
==== Paroloni ====<br />
<br />
Facciamo una pausa per ripassare i paroloni che conosciamo:<br />
<br />
*chiamare una funzione si dice ''invocare'' una funzione;<br />
*la variabile (o le variabili) delle funzioni che aspettano valori in arrivo e sono scritte tra parentesi tonde si chiamano ''parametri''<nowiki>;</nowiki><br />
*i ''references'' si possono chiamare anche ''variabili riferimento'' o ''riferimenti''.<br />
<br />
Per dire che il compilatore ci mette a disposizione della memoria (ad es., quando definiamo una variabile) ho usato l’espressione ''assegnare''. Questa a mio avviso è una idonea traduzione del verbo inglese ''allocate''. Rimane però il fatto che la maggior parte degli informatici, per motivi a me ignoti, preferisce usare l’espressione ‘allocare’, tant’è che pure il dizionario Treccani è costretto a riportare questo termine, anche se specificando che è “sull’esempio dell’inglese ''to allocate''”.<br />
<br />
Chi gradisce questo neologismo lo usi senza problemi.<br />
<br />
<br/>Aggiungiamo ora un altro parolone.<br />
<br />
All’inizio del file ''main.cpp'' abbiamo sempre trascritto le dichiarazioni di funzione. Abbiamo detto che servono al compilatore per verificare che non ci siano nomi di funzione duplicati.<br />
<br />
Orbene, quelle dichiarazioni di funzione in realtà si chiamano ''prototipi'' (''prototype'') di funzione.<br />
<br />
<br />
<br />
=== I puntatori ===<br />
<br />
Nel JavaScript non ci sono nemmeno i ''pointers'', perciò rimarremo ancorati al nostro C++.<br />
<br />
<br/>I puntatori sono forse l’eredità più potente che il C ha trasmesso al C++, anche se in quest’ultimo sono un po’ meno usati perché spesso basta un comodo ''reference''. Nel loro caso ci accorgeremo presto che non ci sono dubbi sulla loro utilità, ma all’inizio ci verranno un po’ di dubbi del perché mai siano stati inventati.<br />
<br />
Anche nel loro caso, infatti, capire '''cosa sono''' è davvero banale; apprendere '''a cosa servono''' un po’ più faticoso. Ma, come di più, ci sarà anche da chiarire '''come''' si usano perché la loro sintassi è un gocciolino meno amichevole di quella dei ''references''.<br />
<br />
<br/>Allora, intanto la definizione: i ''pointers'', o puntatori, sono delle normali variabili; sono, tra l’altro, variabili facili da usare perché contengono '''solo''' numeri interi; non possono quindi, ad esempio, contenere ''string''<nowiki>; ma hanno una particolarità: il loro valore può essere solo l’</nowiki>'''indirizzo di una variabile'''.<br />
<br />
Questa definizione avrà bisogno di una limatina, ma per ora ci va benissimo.<br />
<br />
<br/>Guardiamoli in faccia:<br />
<pre>int miavar; // questa è una variabile ‘normale’<br />
int* puntatore; // questo è un pointer, o puntatore</pre><br />
Da un punto di vista della dichiarazione, la sintassi di un puntatore è molto semplice: basta scrivere un asterisco alla destra della dichiarazione del tipo di dato.<br />
<br />
Come vedete, non c’è l’obbligo di ‘collegarlo’ immediatamente ad una variabile: un puntatore è una variabile autonoma, che può essere collegata a un’altra variabile oppure no. Questo ci fa subito capire che '''non''' è solo un altro nome per una variabile.<br />
<br />
<br/>Rileggiamo la definizione.<br />
<br />
A qualcuno potrebbe non tornare una cosa: se abbiamo detto che contiene solo numeri interi, perché dichiararlo ''int''? La dichiarazione ''int'' dovrebbe essere sottintesa…<br />
<br />
Questo è un punto su cui torniamo fra pochissimo. Guardiamo prima un aspetto più semplice: il valore contenuto in un ''pointer'' può essere solo l’indirizzo di una variabile.<br />
<br />
Per l’appunto noi abbiamo una variabile a disposizione… Proviamo a vedere cosa succede se passiamo il suo indirizzo al puntatore.<br />
<pre>int miavar; // questa è una variabile ‘normale’<br />
int* puntatore; // questo è un pointer, o puntatore<br />
puntatore = &miavar; // adesso il puntatore contiene l’indirizzo di ‘miavar’</pre><br />
Beh, sembra che l’abbia digerito senza problemi.<br />
<br />
Ma cosa dovrebbe farci supporre tutto questo? Forse che si è creato un qualche tipo di legame fra il puntatore e la variabile? Ebbene sì, è proprio così: dando in pasto al puntatore l’indirizzo della variabile lo abbiamo implicitamente autorizzato a agire sul contenuto della nostra variabile.<br />
<br />
<br/>Un puntatore, quindi, non è un’altra etichetta per uno spazio di memoria, ma è una variabile a sé stante, con i suoi propri ''byte'' a disposizione, che però può essere istruita a ‘prendere di mira’ un’altra variabile. Per tenere di mira quella variabile non vuole sapere l’etichetta che c’è sopra, bensì direttamente il suo indirizzo di memoria; dentro di sé, come valore, terrà copia di quell’indirizzo (che è sempre un numero intero), ma, se glielo chiediamo noi, potrà usare questa informazione per andare a mettere le mani dentro la variabile che sta tenendo di mira.<br />
<br />
Il nome puntatore è quindo molto azzeccato: l’indirizzo di memoria è il mezzo con cui può chiedere al compilatore di accedere alla variabile che punta, senza curarsi di quante e quali siano le etichette che le sono state ‘attaccate’ sopra.<br />
<br />
<br/>Potete già capire quante potenzialità in più ci siano rispetto a un ''reference'': avendo il puntatore il suo spazio di memoria, i suoi propri ''byte'', può con facilità essere istruito a puntare a un’altra variabile: basta dargli il nuovo indirizzo.<br />
<br />
<br/>Vi starete chiedendo: «Ma quindi, se ora scrivessi<br />
<pre>puntatore = 5;</pre><br />
anche il valore di ‘miavar’ diventerebbe 5?»<br />
<br />
Risposta: quasi.<br />
<br />
Avete azzeccato l’idea di fondo, ma il puntatore ha una sua sintassi che va rispettata. Rendiamoci conto che è comunque una variabile con il suo spazio di memoria, quindi '''dobbiamo sempre specificare al compilatore se vogliamo agire ''sul valore del puntatore'' oppure ''sul valore della variabile puntata'''''.<br />
<br />
<br/>L’istruzione soprastante dovrebbe far fare un tentativo al compilatore di inserire il numero 5 nello spazio di memoria del puntatore. In altre parole, di sostituire il valore del puntatore con il numero 5. Il problema è che quello sarebbe poi interpretato come l’indirizzo di una variabile, cosa che porterebbe immediatamente a un errore perché non abbiamo idea di a cosa sia dedicato l'indirizzo n. 5 (lo sa solo il computer).<br />
<br />
Conclusione: il compilatore ve lo impedirà. Si bloccherà e restituirà errore.<br />
<br />
<br/>Per dire a un puntatore che noi intendiamo agire '''sulla variabile di cui ha l’indirizzo''' dobbiamo usare di nuovo l’asterisco. Perciò<br />
<pre>*puntatore = 5;</pre><br />
otterrà esattamente l’effetto sperato: cambierà il valore di ‘miavar’ a 5.<br />
<br />
Ricordiamoci questa regola: usare un asterisco prima di un nome di puntatore istruisce il compilatore ad andare ad agire sulla variabile puntata e '''non''' sul puntatore.<br />
<br />
Vogliamo fare un po’ di prove?<br />
<br />
Provo a suggerire qualche spezzone di codice, ma fate dei tentativi anche da soli.<br />
<br />
<br/>Programma che dà errore (provate a leggere che errore vi dà):<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
int miavar; // questa è una variabile ‘normale’<br />
int* puntatore; // questo è un pointer, o puntatore<br />
puntatore = &miavar; // adesso il puntatore contiene l’indirizzo di ‘miavar’<br />
<br />
miavar = 8;<br />
puntatore = 5; // istruzione proibita<br />
<br />
cout << "miavar = " << miavar << endl;<br />
cout << "puntatore = " << puntatore << endl;<br />
<br />
return 0;<br />
}</pre><br />
Codice un po’ più chiaro (questo compila):<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
int miavar; // questa è una variabile ‘normale’<br />
int* puntatore; // questo è un pointer, o puntatore<br />
puntatore = &miavar; // adesso il puntatore contiene l’indirizzo di ‘miavar’<br />
<br />
miavar = 8;<br />
*puntatore = 5; // ok, agisco sulla variabile puntata<br />
<br />
cout << "miavar = " << miavar << endl;<br />
cout << "indirizzo di 'miavar' = " << puntatore << endl;<br />
cout << "valore puntato = " << *puntatore << endl;<br />
cout << "indirizzo di 'puntatore' = " << &puntatore << endl << endl;<br />
<br />
return 0;<br />
}</pre><br />
Sorpresi dalla penultima istruzione?<br />
<br />
Non ce n’è motivo: il puntatore è una variabile come tutte, con il suo indirizzo di memoria, il suo spazio di memoria, la sua brava etichetta, ecc. ecc.<br />
<br />
La sua unica particolarità è che i valori che contiene sono considerati sempre indirizzi di memoria.<br />
<br />
<br/>Tornando al dubbio precedente, ossia del perché abbiamo fatto seguire il nome del puntatore da ''int'', c’è da capire una cosa su come si legge la dichiarazione di un puntatore.<br />
<br />
Quando scriviamo ''int* nomepuntatore'' non stiamo dicendo al compilatore di costruire un puntatore che abbia come valore numeri interi: un indirizzo di memoria sarà sempre un numero intero. Stiamo invece dicendo al compilatore di costruire un puntatore che dovrà tenere di mira una variabile '''dichiarata ''int'''''.<br />
<br />
Ossia, mentre questo non si può fare:<br />
<pre>string testo;<br />
int* punt;<br />
punt = &testo; // errore! punt deve puntare a una variabile di tipo int</pre><br />
questo invece è corretto:<br />
<pre>string testo;<br />
string* punt;<br />
punt = &testo; // ok. punt nasce per puntare a una variabile di tipo string</pre><br />
In altre parole, quello che noi facciamo è venire incontro alla proverbiale pignoleria del C++ e indicare al compilatore che tipo di dati gestiremo tramite il nostro puntatore.<br />
<br />
Come conseguenza di quanto sopra, ricordiamoci che un puntatore può sempre essere ‘spostato’ verso un’altra variabile, ma solo se il tipo di quella variabile è coerente con la dichiarazione del puntatore.<br />
<br />
<br />
<br />
==== Il gioco dei fiammiferi con i puntatori ====<br />
<br />
Abbiamo detto che i puntatori fanno tutto quello che fanno i ''references'' e anche di più. Se volessimo riscrivere il gioco dei fiammiferi in un modo che fa uso dei puntatori invece che dei ''references'', ci potremmo riuscire?<br />
<br />
Proviamo:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
void spiegazioni();<br />
void mossaCane(int *fiammiferi);<br />
void mossaAnatra(int *fiammiferi);<br />
<br />
int main()<br />
{<br />
spiegazioni();<br />
int fiammiferi = 21;<br />
<br />
do {<br />
mossaCane(&fiammiferi);<br />
mossaAnatra(&fiammiferi);<br />
} while ( 1 < fiammiferi );<br />
<br />
cout << endl << "* * * * * * * * * * * * * * * * * * * * * * * * * * *"<br />
<< endl;<br />
cout << "Mi spiace, sei rimasto con l'ultimo"<br />
" fiammifero..." << endl;<br />
cout << "Ho vinto io." << endl;<br />
cout << "* * * * * * * * * * * * * * * * * * * * * * * * * * *"<br />
<< endl << endl;<br />
<br />
return 0;<br />
}<br />
<br />
void spiegazioni()<br />
{<br />
cout << "Ci sono 21 fiammiferi." << endl;<br />
cout << "Ne possiamo prendere da 1 a 4 per volta." << endl;<br />
cout << "Chi rimane con l'ultimo ha perso." << endl;<br />
cout << endl << "Hai la prima mossa." << endl << endl;<br />
}<br />
<br />
void mossaCane(int* fiammiferi)<br />
{<br />
int presa = 0;<br />
<br />
while ( presa < 1 || presa > 4 ) {<br />
<br />
cout << "Quanti fiammiferi prendi (da 1 a 4)? " << endl;<br />
cin >> presa;<br />
<br />
if ( presa < 1 || presa > 4) {<br />
cout << "Spiacente. Devi prendere almeno un fiammifero, "<br />
"ma non più di quattro..." << endl << endl;<br />
}<br />
<br />
}<br />
<br />
*fiammiferi -= presa;<br />
cout << "Hai preso " << presa << " fiammiferi." << endl;<br />
cout << "Ne rimangono " << *fiammiferi << "." << endl;<br />
}<br />
<br />
void mossaAnatra(int* fiammiferi)<br />
{<br />
int presa;<br />
<br />
if ( 1 < *fiammiferi ) {<br />
presa = *fiammiferi - 1;<br />
}<br />
if ( 6 < *fiammiferi ) {<br />
presa = *fiammiferi - 6;<br />
}<br />
if ( 11 < *fiammiferi ) {<br />
presa = *fiammiferi - 11;<br />
}<br />
if ( 16 < *fiammiferi ) {<br />
presa = *fiammiferi - 16;<br />
}<br />
<br />
*fiammiferi -= presa;<br />
<br />
cout << "Io prendo " << presa << " fiammiferi." << endl;<br />
cout << "Adesso ne rimangono " << *fiammiferi << "." << endl<br />
<< endl;<br />
}</pre><br />
Adesso guardiamo insieme i pochi punti che meritano un po’ di attenzione, ma non ci dovrebbero essere difficoltà.<br />
<br />
In pratica, dove c’erano i ''references'' abbiamo messo i puntatori. La sorpresa è che ci tocca stare più attenti a ciò che facciamo, non meno!<br />
<br />
Le dichiarazioni delle funzioni, o per meglio dire i ''prototipi'' di funzione (ricordate?), sono cambiati in modo minimo da così:<br />
<pre>int mossaCane(int fiammi_cane);<br />
int mossaAnatra(int fiammi_anatra);</pre><br />
a così:<br />
<pre>void mossaCane(int *fiammiferi);<br />
void mossaAnatra(int *fiammiferi);</pre><br />
Ossia: i parametri delle due funzioni non sono più references, bensì pointers.<br />
<br />
<br/>La prima differenza vera la troviamo all’interno di ''main()'':<br />
<br />
mossaCane(&fiammiferi);<br />
<br />
mossaAnatra(&fiammiferi);<br />
<br />
Giacché ad attendere i valori c’è un puntatore, e un puntatore '''può contenere solo indirizzi di variabile''', in entrambi i casi dobbiamo spedire l’indirizzo della variabile ‘fiammiferi’.<br />
<br />
<br/>All’interno delle due funzioni ''mossaCane()'' e ''mossaAnatra()'' dovremo poi stare molto attenti: tutte le volte che vogliamo accedere al valore contenuto nella variabile originaria, ossia di ‘fiammiferi’ contenuta in ''main()'', dovremo far precedere in nome del puntatore dall’asterisco:<br />
<pre>*fiammiferi -= presa;</pre><br />
Infatti il segno ‘*’ dice al compilatore: «non devi agire sul valore del puntatore, ma sul valore della variabile puntata!»<br />
<br />
In particolare, non dobbiamo farci ingannare dal fatto che abbiamo dato al puntatore di ''mossaCane()'' e ''mossaAnatra()'' lo stesso nome (‘fiammiferi’) della variabile contenuta in ''main()''! Per il compilatore sono tre cose diverse (hanno 3 indirizzi di memoria diversi!) e non farà confusione, ma la nostra mente può rimanere disorientata.<br />
<br />
<br/>Insomma, che conclusione possiamo trarre? Non so voi, ma a me, leggendo il codice (ma anche scrivendolo!), il primo pensiero che viene in mente è: “che pacchia sono i riferimenti! Guarda un po’ quanti asterischi mi tocca mettere, sopra tutto in ''mossaAnatra()''… E poi mi devo ricordare di mettere il simbolo ‘&’ nella chiamata di funzione, in ''main()'', per passare l’indirizzo della variabile e non il valore… Insomma, questi ''pointers'' sono proprio una gran cosa, ma quando può bastare un riferimento…”<br />
<br />
Questa idea è del tutto personale, è ovvio, e potreste trovare un’infinità di persone che la vedono in maniera opposta a me, ma è anche vero che i riferimenti sono usatissimi.<br />
<br />
Possiamo dire che, se il problema è solo accedere a una variabile da una funzione diversa da quella in cui è definita, un ''reference'' può bastare.<br />
<br />
<br/>Ci restano da scoprire le cose meravigliose che un ''reference'' non può fare.<br />
<br />
<br />
<br />
==== Puntare a un puntatore e puntare a un references ====<br />
<br />
Cerchiamo un altro dettaglio nascosto.<br />
<br />
Cominciamo da questo programma:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
string testo1 = "Il buongiorno si vede dal mattino";<br />
string* p_testo1 = &testo1; // puntatore a testo1<br />
string& r_testo1 = testo1; // riferimento a testo1<br />
<br />
cout << "testo1 = " << testo1 << endl;<br />
cout << endl;<br />
cout << "indirizzo di 'testo1' = " << (unsigned long int) &testo1 << endl;<br />
cout << endl;<br />
cout << "- - - CONFRONTO TRA I DATI DEL PUNTATORE E QUELLI DEL RIFERIMENTO - - -" << endl;<br />
cout << endl;<br />
cout << "valore p_testo1 = " << (unsigned long int) p_testo1 << endl;<br />
cout << "valore r_testo1 = " << r_testo1 << endl;<br />
cout << endl;<br />
cout << "valore variabile puntata da p_testo1 = " << *p_testo1 << endl;<br />
cout << "valore variabile puntata da r_testo1 = " << r_testo1 << endl;<br />
cout << endl;<br />
cout << "indirizzo di p_testo1 = " << (unsigned long int) &p_testo1 << endl;<br />
cout << "indirizzo di 'r_testo1' = " << (unsigned long int) &r_testo1 << endl << endl;<br />
<br />
return 0;<br />
}</pre><br />
Il cui output è il seguente:<br />
<br />
<br/>[[File:Qt III 07.png|Qt_III_07.png]]<br />
<br />
Come al solito, i vostri numeri saranno diversi.<br />
<br />
Cominciamo dalle cose che abbiamo già detto: l’indirizzo di ‘testo1’ e l’indirizzo di ‘r_testo1’ sono uguali. Infatti ‘r_testo1’ è solo un altro nome per ‘testo1’.<br />
<br />
Per la stessa ragione, “valore di r_testo1” e “valore della variabile puntata da r_testo1” danno lo stesso numero: infatti non abbiamo mai detto che un ''reference'' punta una variabile, bensì che è un ''alias'' di quella variabile.<br />
<br />
Ancora: se proviamo ad ottenere l’indirizzo di ‘r_testo1’ otteniamo l’indirizzo di ‘tetso1’, esattamente ciò che ci aspetteremmo da un alias.<br />
<br />
<br/>Il puntatore è invece completamente diverso. Il '''valore''' del puntatore, ossia il dato contenuto nello spazio di memoria etichettato ‘p_testo1’, è l’indirizzo di ‘testo1’.<br />
<br />
L’indirizzo di ‘p_testo1’ è completamente diverso.<br />
<br />
Fin qui ci eravamo già arrivati.<br />
<br />
<br/>Complichiamoci un po’ la vita aggiungendo qualche riga al programma:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
string testo1 = "Il buongiorno si vede dal mattino";<br />
string* p_testo1 = &testo1; // puntatore a testo1<br />
string& r_testo1 = testo1; // riferimento a testo1<br />
<br />
// Introduco un nuovo puntatore.<br />
// A questo puntatore passo il valore di p_testo1<br />
// Il valore di p_testo1 è l'indirizzo di testo1<br />
string* punta_a_punta = p_testo1;<br />
<br />
// Introduco un nuovo riferimento.<br />
// Associo questo riferimento a r_testo1.<br />
// r_testo1 è un alias di testo1.<br />
string& rif_a_rif = r_testo1;<br />
<br />
cout << "testo1 = " << testo1 << endl;<br />
<br />
cout << endl;<br />
cout << "indirizzo di testo1 = " << (unsigned long int) &testo1 << endl;<br />
<br />
cout << endl;<br />
cout << "- - - CONFRONTO TRA I DATI DEI PUNTATORE E QUELLI DEI RIFERIMENTI - - -" << endl;<br />
<br />
cout << endl;<br />
cout << "valore p_testo1 = " << (unsigned long int) p_testo1 << endl;<br />
cout << "valore punta_a_punta = " << (unsigned long int) punta_a_punta << endl;<br />
cout << "valore r_testo1 = " << r_testo1 << endl;<br />
cout << "valore rif_a_rif = " << rif_a_rif << endl;<br />
<br />
cout << endl;<br />
cout << "valore variabile puntata da p_testo1 = " << *p_testo1 << endl;<br />
cout << "valore variabile puntata da punta_a_punta = " << *punta_a_punta << endl;<br />
cout << "valore variabile puntata da r_testo1 = " << r_testo1 << endl;<br />
cout << "valore variabile puntata da rif_a_rif = " << rif_a_rif << endl;<br />
<br />
cout << endl;<br />
cout << "indirizzo di p_testo1 = " << (unsigned long int) &p_testo1 << endl;<br />
cout << "indirizzo di punta_a_punta = " << (unsigned long int) &punta_a_punta << endl;<br />
cout << "indirizzo di r_testo1 = " << (unsigned long int) &r_testo1 << endl;<br />
cout << "indirizzo di rif_a_rif = " << (unsigned long int) &rif_a_rif << endl << endl;<br />
<br />
return 0;<br />
}</pre><br />
State cominciando a odiarmi?&nbsp;:)<br />
<br />
Coraggio, la cosa è assai meno brutta di quello che sembra. Anche il nuovo puntatore e il nuovo riferimento stanno infatti facendo ciò che ci si aspettava da loro.<br />
<br />
<br/>[[File:Qt III 08.png|Qt_III_08.png]]<br />
<br />
Il nuovo riferimento, ‘rif_a_rif’, '''pur essendo stato definito a partire da ‘r_testo1’''' e non ‘testo1’, è comunque diventato un nuovo nome per la variabile ‘testo1’. Il suo valore è il valore di ‘testo1’ e il suo indirizzo è l’indirizzo di ‘testo1’.<br />
<br />
<br/>Anche in questo caso il nuovo puntatore conferma invece di essere una variabile separata con un suo indirizzo separato.<br />
<br />
Anche il nuovo puntatore punta a ‘testo1’, ma perché gli abbiamo detto:<br />
<pre>string* punta_a_punta = p_testo1;</pre><br />
Poiché ‘r_testo1’ contiene indirizzo di ‘testo1’, e l’istruzione precedente copia i valori di una variabile dentro l’alta, adesso in ‘punta_a_punta’ è contenuto l’indirizzo di ‘testo1’.<br />
<br />
<br/>Domanda: cosa succederebbe se decidessimo di non copiare il valore contenuto in ‘p_testo1’ in ‘punta_a_punta’, bensì di dargli in pasto l’indirizzo di ‘p_testo1’?<br />
<br />
In altre parole, a seguente istruzione:<br />
<pre>string* punta_a_punta = &p_testo1;</pre><br />
sarà lecita? E dove ci poterà?<br />
<br />
Vogliamo provare?<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
string testo1 = "Il buongiorno si vede dal mattino";<br />
string* p_testo1 = &testo1; // puntatore a testo1<br />
string& r_testo1 = testo1; // riferimento a testo1<br />
<br />
// Introduco un nuovo puntatore.<br />
// A questo puntatore passo l'indirizzo di p_testo1<br />
string* punta_a_punta = &p_testo1;<br />
<br />
// Introduco un nuovo riferimento.<br />
// Associo questo riferimento a r_testo1.<br />
// r_testo1 è un alias di testo1.<br />
string& rif_a_rif = r_testo1;<br />
<br />
cout << "testo1 = " << testo1 << endl;<br />
<br />
cout << endl;<br />
cout << "indirizzo di testo1 = " << (unsigned long int) &testo1 << endl;<br />
<br />
cout << endl;<br />
cout << "- - - CONFRONTO TRA I DATI DEI PUNTATORE E QUELLI DEI RIFERIMENTI - - -" << endl;<br />
<br />
cout << endl;<br />
cout << "valore p_testo1 = " << (unsigned long int) p_testo1 << endl;<br />
cout << "valore punta_a_punta = " << (unsigned long int) punta_a_punta << endl;<br />
cout << "valore r_testo1 = " << r_testo1 << endl;<br />
cout << "valore rif_a_rif = " << rif_a_rif << endl;<br />
<br />
cout << endl;<br />
cout << "valore variabile puntata da p_testo1 = " << *p_testo1 << endl;<br />
cout << "valore variabile puntata da punta_a_punta = " << *punta_a_punta << endl;<br />
cout << "valore variabile puntata da r_testo1 = " << r_testo1 << endl;<br />
cout << "valore variabile puntata da rif_a_rif = " << rif_a_rif << endl;<br />
<br />
cout << endl;<br />
cout << "indirizzo di p_testo1 = " << (unsigned long int) &p_testo1 << endl;<br />
cout << "indirizzo di punta_a_punta = " << (unsigned long int) &punta_a_punta << endl;<br />
cout << "indirizzo di r_testo1 = " << (unsigned long int) &r_testo1 << endl;<br />
cout << "indirizzo di rif_a_rif = " << (unsigned long int) &rif_a_rif << endl << endl;<br />
<br />
return 0;<br />
}</pre><br />
Il codice è identico a prima; ho solo sostituito queste righe:<br />
<pre>// Introduco un nuovo puntatore.<br />
// A questo puntatore passo il valore di p_testo1<br />
// Il valore di p_testo1 è l'indirizzo di testo1<br />
string* punta_a_punta = p_testo1;</pre><br />
con queste:<br />
<pre>// Introduco un nuovo puntatore.<br />
// A questo puntatore passo l'indirizzo di p_testo1<br />
string* punta_a_punta = &p_testo1;</pre><br />
Sembrerebbe una cosa innocua, ma… Ahia! Il compilatore si arrabbia e non ci fa proseguire. Il messaggio di errore è inequivocabile.<br />
<br />
<br/>[[File:Qt III 09.png|Qt_III_09.png]]<br />
<br />
A voi forse non dirà niente, ma abbiamo compiuto uno dei gesti che il C++ considera più ignominiosi: abbiamo sbagliato a dichiarare il tipo di una variabile!<br />
<br />
<br/>Mi spiego meglio. Noi abbiamo cercato di salvare l’indirizzo di un puntatore dentro un altro puntatore. L’operazione che noi vogliamo compiere non è di per sé proibita, ma bisogna dar ragione al compilatore quando ci avverte che non ha alcun senso.<br />
<br />
Ragioniamoci su. Cosa ce ne faremmo mai di un indirizzo di memoria se quell’indirizzo non ci servisse a recuperare i dati presenti in quella cella di memoria?<br />
<br />
Per meglio dire, quali sono i dati che ci interessano, quelli che abbiamo salvato noi o gli indirizzi di memoria di dove li abbiamo messi? Beh, la risposta è scontata: ci interessano solo i dati su cui dobbiamo lavorare, ossia quelli che abbiamo inserito nella variabile, qualunque sia il tipo della variabile.<br />
<br />
<br/>Il fatto che poi abbiamo deciso di gestirli tramite un puntatore è solo un problema di comodità. A chi interessa qual è l’indirizzo della variabile puntata? L’unica cosa che ci interessa è sapere che è quello contenuto nel puntatore. La prossima volta che faremo girare il programma, sarà un indirizzo diverso, ma l’istruzione<br />
<pre>*p_testo1</pre><br />
ci consegnerà sempre il risultato.<br />
<br />
Ma allora… perché mai ci dovremmo preoccupare di salvare l’indirizzo del puntatore da qualche altra parte?<br />
<br />
<br/>C’è un’unica spiegazione: noi vogliamo usare il nuovo puntatore, ‘punta_a_punta’, per arrivare, in un modo o nell’altro, all’unica cosa che ci può interessare, ossia i dati che abbiamo salvato; in altre parole, a ‘testo1’!<br />
<br />
Questo si può fare, certo, ma… Attenzione! Bisogna essere ben chiari quando si ha a che fare con un compilatore C++.<br />
<br />
Guai a cercare di prenderlo per scemo. Quello che stiamo cercando di creare non è un puntatore ‘normale’, perché altrimenti non gli passeremmo una cosa inutile come l’indirizzo di un altro puntatore.<br />
<br />
Noi stiamo cercando di creare un nuovo tipo di puntatore, '''il puntatore a puntatore''', che sarà autorizzato a portarci, come su un tappeto magico, fin dentro ‘testo1’.<br />
<br />
Allora basta dirlo chiaro e il compilatore ce lo lascerà fare:<br />
<pre>string* punta_a_punta = &p_testo1;</pre><br />
non compila, ma<br />
<pre>string** punta_a_punta = &p_testo1;</pre><br />
sì!<br />
<br />
L’unico problema è che, per ottenere il risultato che vogliamo noi, dovremo anche cambiare<br />
<pre>cout << "valore variabile puntata da punta_a_punta = " << *punta_a_punta << endl;</pre><br />
in<br />
<pre>cout << "valore variabile puntata da punta_a_punta = " << **punta_a_punta << endl;</pre><br />
Provare per credere.<br />
<br />
Non sto a ricopiarvi qui il codice, visto che si devono cambiare solo 2 asterischi, ma con le modifiche sopra riportate funziona al 100%.<br />
<br />
<br/>Adesso non ci resta che farci la stessa domanda sul ''reference''. Sarà possibile ottenere un riferimento di un riferimento? E il puntatore a un riferimento? Non ci resta che provare.<br />
<br />
Modificate le righe<br />
<pre>// Introduco un nuovo riferimento.<br />
// Associo questo riferimento a r_testo1.<br />
// r_testo1 è un alias di testo1.<br />
string& rif_a_rif = r_testo1;</pre><br />
in<br />
<pre>// Introduco un nuovo riferimento.<br />
// Passo a questo riferimento l'indirizzo di r_testo1.<br />
string& rif_a_rif = &r_testo1;</pre><br />
Il compilatore vi bloccherà e non vi farà proseguire.<br />
<br />
Anche se provate a cambiare l’ultima riga in:<br />
<pre>string&& rif_a_rif = &r_testo1;</pre><br />
non otterrete alcun risultato. Come pure<br />
<pre>string&& rif_a_rif = r_testo1;</pre><br />
è proibita.<br />
<br />
<br/>Non c’è niente da fare, non possiamo cambiare la regola del riferimento: il riferimento, al momento della creazione, deve essere associato a una variabile. Non esistono i ''references'' di ''references''.<br />
<br />
È una cosa che si può fare con i puntatori, ma non si può fare con i ''references''.<br />
<br />
<br/>Ma un puntatore a ''reference'' si può fare? Certo, perché no? Essendo però il ''reference'' un altro nome per una variabile, l’unica cosa che otterremo è un ''pointer'' alla variabile originaria. Eccolo qui:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
string testo1 = "Il buongiorno si vede dal mattino";<br />
string* p_testo1 = &testo1; // puntatore a testo1<br />
string& r_testo1 = testo1; // riferimento a testo1<br />
<br />
// Introduco un nuovo puntatore.<br />
// A questo puntatore passo l'indirizzo di p_testo1<br />
string** punta_a_punta = &p_testo1;<br />
<br />
string& rif_a_rif = r_testo1;<br />
<br />
// Introduco ancora un altro puntatore.<br />
// Passo a questo puntatore l'indirizzo di rif_a_rif.<br />
string* punta_a_rif = &rif_a_rif;<br />
<br />
cout << "testo1 = " << testo1 << endl;<br />
<br />
cout << endl;<br />
cout << "indirizzo di testo1 = " << (unsigned long int) &testo1 << endl;<br />
<br />
cout << endl;<br />
cout << "- - - CONFRONTO TRA I DATI DEI PUNTATORE E QUELLI DEI RIFERIMENTI - - -" << endl;<br />
<br />
cout << endl;<br />
cout << "valore p_testo1 = " << (unsigned long int) p_testo1 << endl;<br />
cout << "valore punta_a_punta = " << (unsigned long int) punta_a_punta << endl;<br />
cout << "valore punta_a_rif = " << (unsigned long int) punta_a_rif << endl;<br />
cout << "valore r_testo1 = " << r_testo1 << endl;<br />
cout << "valore rif_a_rif = " << rif_a_rif << endl;<br />
<br />
cout << endl;<br />
cout << "valore variabile puntata da p_testo1 = " << *p_testo1 << endl;<br />
cout << "valore variabile puntata da punta_a_punta = " << **punta_a_punta << endl;<br />
cout << "valore variabile puntata da punta_a_rif = " << *punta_a_rif << endl;<br />
cout << "valore variabile puntata da r_testo1 = " << r_testo1 << endl;<br />
cout << "valore variabile puntata da rif_a_rif = " << rif_a_rif << endl;<br />
<br />
cout << endl;<br />
cout << "indirizzo di p_testo1 = " << (unsigned long int) &p_testo1 << endl;<br />
cout << "indirizzo di punta_a_punta = " << (unsigned long int) &punta_a_punta << endl;<br />
cout << "indirizzo di punta_a_rif = " << (unsigned long int) &punta_a_rif << endl;<br />
cout << "indirizzo di r_testo1 = " << (unsigned long int) &r_testo1 << endl;<br />
cout << "indirizzo di rif_a_rif = " << (unsigned long int) &rif_a_rif << endl << endl;<br />
<br />
return 0;<br />
}</pre><br />
Ed ecco il risultato:<br />
<br />
<br/>[[File:Qt III 10.png|Qt_III_10.png]]<br />
<br />
Vi state domandando: «Ma che ce ne faremo mai di un puntatore a puntatore?»<br />
<br />
Calma! Li incontriamo oggi per la prima volta e già volete sapere tutto?&nbsp;:-)<br />
<br />
I puntatori sono marchingegni complicati e presentano aspetti che ci porterebbero via troppo tempo, se dovessimo dettagliarli tutti, mentre invece noi abbiamo fretta di arrivare agli ''oggetti'' e alle librerie Qt.<br />
<br />
<br/>Allora leviamoci in tre parole anche il prossimo punto.<br />
<br />
<br />
<br />
==== I puntatori e gli array; nonché l’aritmetica di puntatori ====<br />
<br />
Dovete sapere che a casa ho un cimelio: una copia della seconda edizione di “The C programming language.” di Brian W. Kernighan e Dennis M. Ritchie. Dalla lettura del colophon pare che abbia più di un quarto di secolo. Forse dovrei custodirlo religiosamente in una teca di cristallo&nbsp;:-)<br />
<br />
<br/>Per essere sicuro di non perdere per strada le cose più importanti, l’ho ripreso in mano e ho consultato il capitolo 5: “Pointers and Arrays”. Beh, mi ci è voluto poco per convincermi che l’argomento, ora come ora, è impossibile da trattare.<br />
<br />
Quindi mi dovete credere per fede se vi dico che qualunque cosa vogliate fare con un array, la potete fare con un puntatore – non è però vero il contrario!<br />
<br />
<br/>C’è una cosa che mi consola: non useremo granché gli ''array'' visto che nel C++ ci sono i ''vector''; inoltre le librerie Qt ci libereranno della maggioranza dei problemi. Perciò riusciremo a evitare l’aritmetica dei puntatori ancora per un sacco di tempo.<br />
<br />
La mia idea è quindi di rimandare l’argomento a quando davvero sarà necessario.<br />
<br />
<br/>D’altronde l’aritmetica dei puntatori in altri linguaggi, come ad esempio il Java, non esiste e da alcuni è vista come il fumo negli occhi. Anche noi per ora cercheremo di scansarla.<br />
<br />
<br />
<br />
==== Puntatori a funzione ====<br />
<br />
Una cosa che potrebbe sorprendervi è scoprire che un puntatore può ‘tenere di mira’, invece che una variabile, una funzione.<br />
<br />
<br/>Anche su questo argomento ho cercato ispirazione nel buon Kernighan-Ritchie appena citato, e quello che ne ho ottenuto è questo sobrio esempio:<br />
<pre>qsort((void **) lineptr, 0, nlines-1,<br />
(int (*)(void*,void*))(numeric&nbsp;? numcmp&nbsp;: strcmp));</pre><br />
Non ditemi che non è chiaro&nbsp;:)<br />
<br />
Ok, diciamo che l’argomento non è ‘soffice’, ma vedrete che riusciremo ad ammorbidirlo.<br />
<br />
Intanto mettiamoci d’accordo sul '''come''' funziona.<br />
<br />
<br/>Cosa avevamo detto che era un funzione? In buona sostanza è un blocco di codice con un nome. Quando si usa quel nome, il compilatore si precipita a eseguire il codice contenuto nella funzione. Se vogliamo, possiamo dotare la nostra funzione di ''parametri'' e passargli degli ''argomenti''. Sempre se vogliamo, possiamo chiedere che ci restituisca un valore.<br />
<br />
Per poter eseguire una funzione, il compilatore deve prima caricarla in memoria. Se si tiene in mente questo, si capisce che alla fin fine una funzione occupa uno spazio di memoria né più né meno che una variabile.<br />
<br />
Se la memoria del computer fosse un oggetto fisico e potessimo posarlo sul tavolo davanti a noi, qualcuno potrebbe chiederci: «Mi fai vedere la differenza tra una variabile e una funzione?»<br />
<br />
E noi, per assurdo, avremmo molte difficoltà a rispondergli. Infatti potremmo trovarci davanti molti spazi di memoria contrassegnati da etichette e alcuni di questi potrebbero essere variabili e altri funzioni. Tirando a indovinare, tra gli spazi di memoria etichettati, quelli più piccoli saranno variabili e quelli più grandi funzioni. Ma è solo un tirare a indovinare!<br />
<br />
<br/>È vero che una variabile è uno spazio di memoria riservato a noi, in cui possiamo intervenire a nostro piacimento, mentre una funzione è caricata in uno spazio di memoria che il compilatore si gestisce come vuole lui; però alla fine sono spazi di memoria con dei nomi.<br />
<br />
Pertanto, come posso ‘puntare’ uno spazio di memoria etichettato che contiene dei dati, così posso ‘puntare’ uno spazio di memoria che contiene delle istruzioni.<br />
<br />
Come poi funzioni all’atto pratico non è un problema mio: ci pensa il compilatore. L’unica cosa che io devo fare è dire al compilatore che il puntatore che vado a dichiarare deve puntare a una funzione. Fine. Tutte le questioni tecniche, poi, se le sbrigherà lui.<br />
<br />
<br/>Adesso vediamo come si fa a dichiarare un puntatore a funzione.<br />
<br />
E qui ci troviamo nei guai. E sì, perché un puntatore è, si è già detto, una normale variabile, solo che il suo contenuto è interpretato come un indirizzo di memoria. Essendo una normale variabile, può essere usato per restituire un valore alla funzione chiamante. Ossia, all’interno di una funzione posso scrivere:<br />
<pre>string *miafunzione()<br />
{<br />
string* testo = “Testo da restituire”;<br />
<br />
// un sacco di istruzioni<br />
…<br />
<br />
return testo; // restituisco un puntatore<br />
}</pre><br />
Anzi, questo sarà un altro punto che dovremo trattare sui puntatori. Ma quel che ora mi preme sottolineare è come viene dichiarata una funzione che restituisce un puntatore.<br />
<br />
Se la funzione restituisce un puntatore a ''string'', la sintassi sarà:<br />
<pre>string *nomefunzione()</pre><br />
In effetti non cambia niente rispetto alla dichiarazione ‘normale’. Se una funzione deve restituire un ''int'', scriviamo ''int nomefunzione()'', se deve restituire un puntatore a ''int'', ossia un ''int*'', allora scriveremo ''int *nomefunzione()''.<br />
<br />
In realtà non facciamo altro che rispettare la regola: scriviamo il tipo di dato che la funzione restituisce prima del nome di funzione. Badate bene che lo spazio non ha alcuna rilevanza; in altre parole, le tre espressioni:<br />
<pre>int* nomefunzione() // spazio tra asterisco e nomefunzione<br />
int *nomefunzione() // spazio tra int e asterisco<br />
int * nomefunzione() // spazio prima e dopo l’asterisco</pre><br />
per il compilatore sono identiche! L’abitudine a mettere l’asterisco attaccato al nome di funzione serve solo a migliorare la leggibilità del codice per quei poveri tontoloni degli esseri umani, ma non ha alcun effetto sul compilatore.<br />
<br />
A questo punto ci dobbiamo chiedere: «Se metto un asterisco prima del nome di funzione, allora dico al compilatore che la funzione restituisce un puntatore. Se è così, '''come faccio a dire al compilatore che voglio un puntatore a funzione?'''»<br />
<br />
<br/>Se non è chiaro qual è il problema, diamo un’occhiata al codice che segue:<br />
<pre>// La seguente funzione non fa nulla di utile e<br />
// in un programma vero non si troverebbe mai.<br />
// Serve solo per far capire il problema.<br />
int* miafunzione()<br />
{<br />
int miavariabile = 78; // numero a caso<br />
int* miopunt = &miavariabile;<br />
return miopunt;<br />
}<br />
<br />
int main()<br />
{<br />
int var1 = 5;<br />
<br />
// Per creare un puntatore alla variabile precedente<br />
// devo mettere asterisco dopo la dichiarazione di tipo.<br />
int* punt1 = &var1;<br />
<br />
// Adesso voglio creare un puntatore che punti <br />
// alla funzione miafunzione()<br />
// miafunzione() restituisce un int, perciò<br />
// ipotizzo di dover dichiarare un puntatore a int<br />
// Dove piazzerò l’asterisco?<br />
<br />
// La seguente definizione è sbagliata:<br />
int* punt2 = &miafunzione();<br />
}</pre><br />
Per il compilatore del C++ quello che ho scritto sopra è inaccettabile.<br />
<br />
Quando definisco un puntatore il compilatore vuole che specifichi con precisione a quale tipo di dati dovrà puntare. È per questo che specifichiamo ''int*'' o ''string*'' prima di indicare il nome che vogliamo dare al puntatore. Se un puntatore è dichiarato ''int*'', si aspetta di tenere di mira uno spazio di memoria di un certo numero di byte (sul mio computer, 4); questo significa che ignorerà il byte successivo (nel mio caso, il 5°).<br />
<br />
In altre parole sul mio computer le istruzioni:<br />
<pre>int var1 = 5;<br />
int* punt1 = &var1;</pre><br />
creano una variabile che occupa 4 byte e un puntatore che tiene d’occhio quella variabile. Io non potrò mai sapere cose c’è nella cella di memoria successiva perché, sia che io passi al compilatore il nome della variabile, sia che gli passi il nome del puntatore preceduto da asterisco, per il mio compilatore un ''int'' è composto da 4 byte e non mi farà accedere al 5°.<br />
<br />
Adesso rileggiamo la mia ultima istruzione:<br />
<pre>int* punt2 = &miafunzione();</pre><br />
Con questa riga io pretenderei dal compilatore che creasse un puntatore, di nome ‘punt2’, che puntasse a uno spazio di memoria equivalente a un int, ossia, sul mio computer, a 4 byte. Ma poi gli assegno lo spazio di memoria occupato da un’intera funzione!<br />
<br />
Ma poco fa abbiamo detto che lo spazio di memoria occupato da una funzione di solito è più grande di quello occupato da una variabile; in questo caso possiamo darlo per garantito: non credo proprio che possa esistere una funzione che, una volta caricata in memoria, possa occupare solo 4 byte!<br />
<br />
<br/>E infatti il compilatore non accetterà mai questa mia pretesa. La mia dichiarazione di tipo è sbagliata: non devo chiedere al compilatore di puntare a uno spazio di memoria di tipo ''int'', bensì di puntare a uno spazio di memoria di tipo “funzione che non ha ''parametri'', ma restituisce un intero’:<br />
<pre>int* punt2();</pre><br />
Cominciate a inquadrare il problema? Se osservate bene la riga qui sopra vi accorgerete subito che non può essere corretta.<br />
<br />
Infatti se nel mio codice si trovasse una funzione che si chiama ''punt2()'', non ha ''parametri'' e ritorna un puntatore a intero, la sua dichiarazione sarebbe per l’appunto:<br />
<pre>int* punt2()</pre><br />
E ciò implica che, all’inizio del codice, fuori da ogni funzione, sarebbe riportato il prototipo di quella funzione, ossia una copia della sua dichiarazione, che sarebbe sempre:<br />
<pre>int* punt2();</pre><br />
Mettiamo insieme i pezzi: cos’altro si trova dichiarato fuori da ogni funzione? Proprio loro: le variabili globali. Ciò significa che ciò che viene dichiarato fuori da ogni funzione ha visibilità globale, ossia viene visto da ogni parte del codice.<br />
<br />
Quindi mi troverei un’istruzione, all’interno di una funzione, che è lettera per lettera identica a un prototipo di funzione che appare nello spazio di visibilità globale.<br />
<br />
<br/>Ma povero compilatore! Non posso certo prendere che gestisca una situazione come questa; in fondo è solo un software. Tocca a me, bipede alla tastiera, risolvere il problema.<br />
<br />
<br/>E infatti la soluzione esiste e non è nemmeno complicata, ma devo ammettere che non è per niente bella: bisogna mettere l’asterisco e il nome di funzione tra parentesi. Ossia: ''(*nomepuntatore)()''.<br />
<br />
Ecco infine la dichiarazione corretta:<br />
<pre>// Puntatore a funzione senza parametri che restituisce un int<br />
int (*punt2)();<br />
<br />
// Assegnazione di una funzione al puntatore precedente:<br />
punt2 = &miafunzione();<br />
<br />
// Oppure le due istruzione precedenti assemblate <br />
// in un’unica riga:<br />
int (*punt2)() = &miafunzione();</pre><br />
Di conseguenza:<br />
<pre>// funzione che restituisce un puntatore a int<br />
int *nomefunzione()<br />
<br />
// puntatore a funzione che restituisce un int<br />
int (*nomepuntatore)() = …<br />
<br />
// puntatore a funzione che restituisce un puntatore a int<br />
int* (*nomepuntatore)() = …</pre><br />
Sì, lo ammetto, è proprio sgradevole. Potevano inventare un sistema migliore.<br />
<br />
L’importante per ora non è fare uso di questa sintassi, ma solo sapere che esiste e capire cosa significhi.<br />
<br />
<br/>Adesso che abbiamo capito '''come''' funziona e '''come si fa''' a dire al compilatore che vogliamo usare questa strana entità che è il puntatore a funzione, la domanda a cui dobbiamo dare una risposta è: «'''Che cosa''' ce ne facciamo di un puntatore a funzione?»<br />
<br />
<br/>Qui si entra un poco nel complicato. I puntatori a funzione hanno una grandissima utilità, ma nel C++ meno che nel C. Infatti nel C++ possono essere sostituiti da cose come il polimorfismo e i ''functor'' che non esistono nel C.<br />
<br />
Potrei anche tirare fuori dal cilindro qualche spezzone di codice di tipo accademico, ma varrà la pena di discuterne visto che non sappiamo bene quando li useremo?<br />
<br />
Forse per ora ci può bastare questa risposta, sulla loro utilità: tramite un puntatore a funzione (''function pointer)'' possiamo invocare una funzione anche senza sapere il suo nome: basta che sia stata in precedenza assegnata a quel puntatore.<br />
<br />
In pratica, come si è detto tante volte, può capitare che questa operazione (di assegnazione) venga compiuta in un’altra parte del codice, che magari non abbiamo scritto noi, ma qualcun altro. Noi ci possiamo disinteressare di cosa ci sia scritto in questa parte del codice: l’unica cosa che ci interessa sapere è che al puntatore ‘x’ è stata assegnata la funzione giusta, quella che noi dobbiamo usare, e a noi ci basta invocarla tramite questo puntatore.<br />
<br />
<br/>Anche nel JavaScript si può assegnare una funzione a una variabile e poi usare la variabile per invocare la funzione.<br />
<br />
<br/>Ci sarà occasione di riprendere l’argomento, ma ora salutiamo i puntatori dando un’occhiata ai loro limiti.<br />
<br />
==== I limiti dei puntatori ====<br />
<br />
Abbiamo visto che non è possibile passare un numero a un ''reference'' (v. sopra, ''I limiti dei references'').<br />
<br />
Si potrà passarlo a un puntatore?<br />
<br />
Si accettano scommesse prima di provare:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
void miafunz(int* punt);<br />
<br />
int main()<br />
{<br />
miafunz(5);<br />
<br />
return 0;<br />
}<br />
<br />
void miafunz(int* punt)<br />
{<br />
cout << "Valore di punt = " << *punt << endl;<br />
}</pre><br />
Ahia! Spiacente. Anche in questo caso il compilatore si oppone. Il parametro ‘punt’ è stato dichiarato puntatore a int e non è disposto ad accettare un ‘semplice’ int: vuole un indirizzo di memoria.<br />
<br />
Domandona: «Ehi! Ma come fa lui a sapere che non è un indirizzo di memoria? È comunque un numero intero. Non potrebbe essere una cella di memoria che ha un indirizzo molto basso? 5, per l’appunto? E se gli passassi un numero molto alto, 3.220.819.138 per esempio, l’accetterebbe?»<br />
<br />
Risposta: no! Non è così facile gabbare il compilatore. Comunque provate pure, se vi va: tentar non nuoce&nbsp;;-)<br />
<br />
<br/>Il problema è che il ''tipo'' non corrisponde; la dichiarazione di tipo di dato, intendo dire. Anche se gli passaste una variabile di tipo ''int'' non la accetterebbe.<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
void miafunz(int* punt);<br />
<br />
int main()<br />
{<br />
int var1 = 5;<br />
miafunz(var1);<br />
<br />
return 0;<br />
}<br />
<br />
void miafunz(int* punt)<br />
{<br />
cout << "Valore di punt = " << *punt << endl;<br />
}</pre><br />
Anche il codice qui sopra è respinto dal compilatore e per lo stesso motivo.<br />
<br />
Se il ''parametro'' della funzione è ''int*'', dobbiamo per forza passare un ''int*'' come abbiamo fatto in ''mossaCane()'' e ''mossaAnatra()'':<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
void miafunz(int* punt);<br />
<br />
int main()<br />
{<br />
int var1 = 5;<br />
int* punt1 = &var1;<br />
miafunz(punt1);<br />
<br />
return 0;<br />
}<br />
<br />
void miafunz(int* punt)<br />
{<br />
cout << "Valore di punt = " << *punt << endl;<br />
}</pre><br />
Finalmente compila.<br />
<br />
<br/>Stessa domanda da un altro punto di vista: nell’esempio precedente, se in ''main()'' provassimo ad assegnare direttamente un intero al puntatore, lo prenderebbe?<br />
<br />
Ossia se cambiassimo da<br />
<pre>int* punt1 = &var1;</pre><br />
a<br />
<pre>int* punt1 = 5;</pre><br />
inganneremmo il compilatore?<br />
<br />
Non credo proprio: neanche qui il tipo di dato corrisponde, giacché 5 è un ''int'' non un ''int*''. Ossia, non è un indirizzo di memoria!<br />
<br />
Anche in questo caso non c’è niente da fare: la regola dice che un puntatore è una variabile che contiene un indirizzo di memoria. Il compilatore lo sa se gli state chiedendo di copiare un indirizzo di memoria o no: è lui che li gestisce!<br />
<br />
<br/>Anche in questo caso, come in quello dei ''references'', parrebbe che esistesse un limite dei puntatori legato al fatto se esista o no una connessione con un’altra variabile.<br />
<br />
Nel caso dei riferimenti, però, il limite è assoluto: il riferimento può nascere solo se viene associato seduta stante con una variabile. Nel caso dei ''pointer'' sembrerebbe un limite di fatto, ma non di sintassi: il ''pointer'' può essere dichiarato, ma non avrebbe alcun utilizzo pratico finché non gli venisse passato un indirizzo di memoria a cui puntare, che sia quello di una variabile (normale, ''reference'' o ''pointer'') o di una funzione – o di un ''oggetto''.<br />
<br />
<br/>Il seguente codice, però, sembra smentire questa ipotesi:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
int* punt1;<br />
<br />
cout << "Se 'punt1' non è stato connesso con nessuna variabile, "<br />
"vuol dire che è vuoto?" << endl;<br />
<br />
cout << "Possiamo dare un'occhiata a cosa c'è dentro al puntatore?" << endl;<br />
<br />
cout << "Certo che sì! Basta *non* usare l'asterisco." << endl << endl;<br />
<br />
cout << "Contenuto di 'punt1' = " << (unsigned long int) punt1 << endl << endl;<br />
<br />
return 0;<br />
}</pre><br />
Il programma ci presenta il seguente risultato:<br />
<br />
<br/>[[File:Qt III 11.png|Qt_III_11.png]]<br />
<br />
Ora andiamo subito alle cose importanti, ma vorrei soffermarmi un attimo sulla prima istruzione ''cout'':<br />
<pre>cout << "Se 'punt1' non è stato connesso con nessuna variabile, "<br />
"vuol dire che è vuoto?" << endl;</pre><br />
Avrete notato che per rendere il codice più leggibile cerco di evitare righe troppo lunghe. A dire il vero di solito si usa farle ancora più corte, ma non ci sono regole ferree in proposito.<br />
<br />
In questo caso, una riga come:<br />
<pre>cout << "Se 'punt1' non è stato connesso con nessuna variabile, vuol dire che è vuoto?" << endl;</pre><br />
sarebbe andata ben oltre la normale lunghezza delle righe in C++.<br />
<br />
Il problema è che tornare a capo all’interno delle frasi chiuse fra virgolette non è consentito. Però il C, e con lui il C++, offre una soluzione semplice al problema: basta chiudere le virgolette e riaprirle subito dopo. Il compilatore capisce che volevate andare a capo e provvede, quando compila il codice, a riattaccare i pezzi della frase fra di loro. È una cosa talmente semplice e comoda che dopo le prime volte viene automatica.<br />
<br />
Quindi a schermo la frase che nel codice ho spezzato in due parti ridiventa unita.<br />
<br />
<br/>Adesso torniamo al nostro puntatore.<br />
<br />
In effetti parrebbe proprio già… attivo. Non contiene già un indirizzo di memoria? Allora perché non dovremmo riuscire ad assegnargli un valore? Potrebbe metterlo lì, no?<br />
<br />
E infatti è così:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
int* punt1;<br />
*punt1 = 5;<br />
<br />
cout << "Contenuto di 'punt1' == " << (unsigned long int) punt1 << endl << endl;<br />
cout << "Contenuto dello spazio di memoria puntato da 'punti1' == "<br />
<< *punt1 << endl << endl;<br />
<br />
return 0;<br />
<br />
}</pre><br />
Pare che siamo riusciti a ingannare il compilatore!<br />
<br />
(Tenete presente la sintassi: '''per accedere al valore dello spazio di memoria tenuto di mira dal puntatore bisogna usare l’asterisco'''. Ve lo ricordavate?)<br />
<br />
<br/>Il programma ci risponde, in apparenza senza difficoltà:<br />
<br />
<br/>[[File:Qt III 12.png|Qt_III_12.png]]<br />
<br />
Quindi sembra filare tutto liscio. Salvo, forse, fare caso a una finestrella che si è aperta in Qt sotto il nostro codice e che pone in bella vista un brutto cartello di pericolo:<br />
<br />
<br/>[[File:Qt III 13.png|Qt_III_13.png]]<br />
<br />
Il nostro amico compilatore sta cercando di aiutarci a non commettere sciocchezze e forse dovremmo ascoltarlo.<br />
<br />
<br/>Cerchiamo di capire dove sta il problema. Il seguente codice, secondo voi, che risultato darà a schermo?<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
int var1;<br />
<br />
cout << "Contenuto di 'var1' == " << var1 << endl << endl;<br />
<br />
return 0;<br />
}</pre><br />
Chi scommette che il risultato sarà: Contenuto di 'var1' == 0&nbsp;?<br />
<br />
Nessuno? Tutti?<br />
<br />
Andiamo a vedere?<br />
<br />
<br/>[[File:Qt III 14.png|Qt_III_14.png]]<br />
<br />
Wow! A me dà un numero negativo…<br />
<br />
A voi? Anche a voi un numero strano e inaspettato?<br />
<br />
<br/>Scusate la domanda, ma… perché inaspettato?<br />
<br />
Qualcuno di noi ha forse detto al compilatore di portare il valore della variabile a 0? Direi di no. E quindi perché avrebbe dovuto farlo?<br />
<br />
Vi ricordate cosa abbiamo detto a preposito della durata delle variabili? Quando una funzione è terminata, il compilatore libera la memoria e la rende disponibile per altre funzioni che debbano essere invocate. Questo significa anche l’opposto: la nostra funzione agisce in una scatola di memoria che, fino a pochi istanti prima, era occupata da altre istruzioni, altre variabili e altri dati.<br />
<br />
Con un istruzione del tipo:<br />
<pre>int miavariabile;</pre><br />
noi chiediamo al compilatore di assegnarci alcuni byte di memoria e attaccarci un’etichetta sopra. Punto.<br />
<br />
Questo significa che, in quei byte, quel che c’era c’è rimasto: ossia ci sono dati e valori che derivano dal codice che vi era in funzione istanti prima.<br />
<br />
<br/>Quel che c’è in una variabile al momento della sua creazione è imprevedibile. In gergo si dice che il suo contenuto è spazzatura.<br />
<br />
<br/>Questo vale per tutte le variabili (che non siano ''oggetti''!), quindi pure per i puntatori. Quello che noi vogliamo considerare come un indirizzo a uno spazio di memoria in realtà è un numero del tutto casuale, che consiste solo nell’avanzo di ciò che c’era in quelle celle pochi istanti prima.<br />
<br />
<br/>È questo che sta cercando di comunicarci il compilatore:<br />
<pre>'punt1' is used uninitialized in this function</pre><br />
significa: «Ehi, tonto! Ti sei dimenticato di inizializzare la variabile prima di usarla.»<br />
<br />
Inizializzare la variabile vuol dire assegnarle un valore, inserisci un dato. In altre parole: «il valore contenuto nella variabile che stai usando è un insieme casuale di byte. Stai andando avanti con della spazzatura.»<br />
<br />
<br/>Badate bene: questo non è proibito! Non c’è una regola del C o del C++ che dice che non lo possiamo fare. Semplicemente è a nostro rischio e pericolo. Diciamo che in generale è una cosa molto sciocca.<br />
<br />
Noi eviteremo di prendere questi rimproveri dal compilatore, quindi assegneremo sempre in modo esplicito uno spazio di memoria al puntatore prima di usarlo.<br />
<br />
<br/>Una curiosità: prima ho scritto che la regola vale per ‘tutte’ le variabili. Beh, non è del tutto vero: le variabili globali vengono inizializzate a zero dal compilatore.<br />
<br />
<br/>A questo punto possiamo correggere la nostra affermazione di prima: non esiste alcun limite per i puntatori in merito all’essere stati connessi o no a una variabile. Esiste senz’altro per i ''reference''. Un puntatore può essere usato, sia da un punto di vista sintattico che ‘logico’, senza che gli sia stato assegnato in modo esplicito un indirizzo di memoria da tenere di mira.<br />
<br />
Però all’atto pratico questa operazione è rischiosa e pressoché priva di senso – sopra tutto se si considera quanto poco ci vuole a creare una variabile e a connetterla al puntatore. In altre parole, usare un puntatore senza avergli assegnato un indirizzo di memoria da puntare è in teoria lecito, ma '''non c’è nessuna garanzia che il codice funzioni''' perché ciò che è contenuto nel puntatore è '''spazzatura'''.<br />
<br />
<br/>Quando definiamo una variabile, il compilatore ha cura di crearla nella zona di memoria più idonea, una zona che poi non toccherà perché saprà che lì ci sono i nostri dati. Ma se usiamo il valore spazzatura contenuto in un puntatore alla sua nascita, beh, stiamo facendo riferimento a uno spazio di memoria che può trovarsi ovunque. Questo significa che non potremo mai sapere se e quando sarà impegnato da qualche altra funzione. I nostri dati potrebbero essere modificati senza preavviso oppure potremmo stare alterando dati in uso da altre parti del programma; o addirittura riscrivendo parti di codice caricate in memoria. Non solo, ma non c’è nessuna garanzia di non andare a toccare un’area di memoria proibita, cosa che costringerebbe il sistema operativo a chiudere forzatamente il nostro programma.<br />
<br />
Insomma, fatta salva la teoria, nella pratica un puntatore va inizializzato con un indirizzo valido prima di poterlo usare.<br />
<br />
<br />
<br />
==== Inizializzazione degli oggetti ====<br />
<br />
Quel che si è detto poco sopra sul contenuto delle variabili appena definite non vale sempre: a differenza delle variabili gli oggetti possono nascere in uno stato coerente, nel senso che a seconda di come sono stati concepiti si può prevedere il valore delle loro proprietà fin da subito.<br />
<br />
In poche parole, un oggetto concepito con cura, quando nasce, nasce sempre allo stesso modo: non contiene codice spazzatura.<br />
<br />
Per ora abbiamo incontrato solo due oggetti, ''vector'' e ''string'', ma si tratta già di due oggetti ‘di qualità’; questo vuol dire che tutti i ''vector'' e tutte le ''string'' che incontreremo nasceranno identici fra di loro.<br />
<br />
Proviamo subito:<br />
<pre>#include <iostream><br />
#include <vector><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
string miastringa; // non assegno alcun valore<br />
vector<int> miovector; // non assegno alcun valore<br />
<br />
if ( miastringa.empty() == true ) {<br />
cout << "miastringa è vuota!" << endl;<br />
}<br />
else {<br />
cout << "ERRORE! miastringa non è vuota alla nascita!!" << endl;<br />
}<br />
<br />
if ( miovector.empty() == true ) {<br />
cout << "miovector è vuoto!" << endl;<br />
}<br />
else {<br />
cout << "ERRORE! miovector non è vuoto alla nascita!!" << endl;<br />
}<br />
<br />
}</pre><br />
empty() è un metodo, cioè una funzione, che esiste sia per string che per vector. In entrambi i casi compie la stessa operazione: ci informa se l’oggetto è vuoto oppure no. Se è vuoto restituisce ‘true’, se invece non è vuoto risponde ‘false’.<br />
<br />
‘true’ e ‘false’ sono anche i valori su cui si basano istruzioni come ''if'' e ''while'', il che vuol dire che le due istruzioni<br />
<pre>if ( miastringa.empty() == true ) {<br />
if ( miovector.empty() == true ) {</pre><br />
avrebbero potuto essere scritte:<br />
<pre>if ( miastringa.empty() ) {<br />
if ( miovector.empty() ) {</pre><br />
e avrebbero funzionato esattamente nello stesso modo.<br />
<br />
In altre parole, se ‘miastringa’ è vuota, dopo il confronto “miastringa.empty() == true” nell’istruzione ''if'' è contenuto il valore ''true'', che starebbe a significare “confronto ok”.<br />
<br />
Se però non facciamo il confronto, dentro l’istruzione ''if'' rimarrà il valore restituito dal metodo ''empty()'', che, se ‘miastringa’ è vuota, sarà sempre ‘true’.<br />
<br />
Perciò in questo caso il confronto è superfluo. Questa comodità spiega perché vengano scritte tante funzioni che restituiscono solo ‘true’ o ‘false’.<br />
<br />
<br/>Se si prova ad aggiungere altri ''vector'' o ''string'' al programma e si testano con il metodo ''empty()'', si scoprirà che la situazione non cambia mai: tutti i ''vector'' e tutte le ''string'' nascono allo stesso modo.<br />
<br />
Gli oggetti che faremo noi saranno invece un po’ meno raffinati&nbsp;:)<br />
<br />
<br/>Il dubbio che può venire ad alcuni è se questa verità vale anche per i puntatori agli oggetti.<br />
<br />
Secondo voi, se scrivo<br />
<pre>string *miastringa;</pre><br />
potrò poi applicarci il metodo empty() e scoprire che è vuota?<br />
<br />
Risposta: ovviamente no, ma se fate un tentativo scoprite cosa vi risponde il compilatore.<br />
<br />
Come prima cosa, è giunto il momento di svelarvi due segreti: il primo è che i puntatori agli oggetti sono usatissimi e se ci pensate un attimo, abbiamo già spiegato come mai.<br />
<br />
Tutte le volte che volessimo passare un nostro oggetto come ''argomento'' a una funzione, dovremmo chiedere al compilatore di fare la copia di chissà quante celle di memoria. Se invece usiamo un puntatore, tutto ciò che facciamo è copiare un singolo numero intero: il massimo dell’efficienza.<br />
<br />
<br/>Il secondo segreto è che, se un oggetto non è dichiarato come variabile, bensì come puntatore, allora non dobbiamo usare il punto per invocare i metodi, bensì il buffo segno ‘->’.<br />
<br />
In altre parole, la sintassi sarebbe la seguente:<br />
<pre>string *miastringa;<br />
if ( miastringa->empty() ) {</pre><br />
Quanto al resto, non cambia nulla, ma questo bisogna ricordarcelo: se è una variabile, allora i metodi si ‘attaccano’ con un punto; se è un puntatore, allora si ‘attaccano’ con un ‘->’.<br />
<br />
<br/>Detto questo, la regola del puntatore non cambia: il puntatore è solo una variabile che contiene valori interi che vengono considerati indirizzi di memoria.<br />
<br />
Il corollario di questa affermazione è che dopo che si è scritto:<br />
<pre>string *miastringa;</pre><br />
l’unica cosa che avremo dichiarato sarà una variabile che contiene valori interi che saranno interpretati come indirizzi di memoria.<br />
<br />
Sembra che stia giocando con le parole, ma non è così: il significato del discorso è: l’oggetto ancora non esiste.<br />
<br />
Noi '''non''' abbiamo detto al compilatore di creare un ''oggetto'' di tipo ''string''. Abbiamo detto che volevamo un puntatore, e questo è ciò che ci sta dando. Il puntatore '''non''' sta puntando a uno spazio di memoria dove è contenuto un oggetto ''string''.: sta puntando uno spazio di memoria dove c’è spazzatura.<br />
<br />
Quando invece scriviamo<br />
<pre>string miastringa;</pre><br />
il compilatore prende un’area di memoria e la riserva per i nostri dati di tipo string. Dopo questa operazione si è soliti dire che l’oggetto esiste, perché occupa una quantità di celle di memoria misurabile, anche se ancora non ci abbiamo inserito alcun valore. Nel nostro caso invece l’oggetto non è stato creato in memoria, quindi non esiste. Non essendoci un oggetto, non siamo autorizzati a invocarne i metodi.<br />
<br />
<br/>Un'alternativa consisterebbe nell’utilizzo della parolina magica ''new'', di cui però andremo a parlare più avanti.<br />
<br />
<br/>Il discorso sui puntatori potrebbe proseguire per chissà quante pagine, ma le cose più importanti le abbiamo accennate, perciò per ora lo chiudiamo qui.<br />
<br />
<br/>L’ultima cosa che ci rimane è un parolone.<br />
<br />
L’operazione di andare a consultare cos’è contenuto in una variabile tramite un puntatore a essa associata si chiama '''''dereferenziazione'''''.<br />
<br />
<br/>Leviamoci un ultimo piccolo ostacolo prima di arrivare agli oggetti, così dopo non ci distrae più niente.<br />
<br />
Stavolta non è nulla di difficile né di concettoso, perciò ce la sbrigheremo in fretta. Si tratta di una ‘raffinatezza’ del C++, che non c’è in tutti i linguaggi, e può lasciare un po’ interdetti la prima volta che la si incontra.<br />
<br />
<br />
<br />
=== Il mascheramento delle variabili ===<br />
<br />
Sappiamo che esistono due spazi di visibilità (''scope''): una visibilità ''globale'' e una ''locale''.<br />
<br />
Quello che non ci siamo mai domandati è se questi spazi possano interferire fra di loro.<br />
<br />
<br/>Supponiamo di avere una variabile globale di questo tipo:<br />
<pre>string testo = "Sono una variabile GLOBALE";</pre><br />
Andando avanti con il nostro programma, ci scordiamo di aver creato quella variabile e ricicliamo lo stesso nome:<br />
<pre>string testo = "Sono una variabile LOCALE";</pre><br />
Secondo voi come reagirà il compilatore? Sceglierà una delle due a suo piacimento? Ci impedirà di compilare il programma? Ci darà un avviso come ha fatto per il puntatore non inizializzato?<br />
<br />
<br/>Nessuna delle tre. Intanto proviamo:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
string testo = "Sono una variabile GLOBALE";<br />
<br />
int main()<br />
{<br />
// Pericolo! 'testo' esiste già<br />
string testo = "Sono una variabile LOCALE";<br />
<br />
cout << testo << endl << endl;<br />
<br />
return 0;<br />
}</pre><br />
L’output è il seguente:<br />
<br />
<br/>[[File:Qt III 15.png|Qt_III_15.png]]<br />
<br />
Il compilatore ha scelto la seconda variabile, quella locale.<br />
<br />
Adesso, visto che ci piace fare esperimenti, insistiamo sulla stessa strada:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
string testo = "Sono una variabile GLOBALE";<br />
<br />
int main()<br />
{<br />
string testo = "Sono una variabile LOCALE";<br />
<br />
if (true) {<br />
string testo = "Sono una variabile in un BLOCCO IF";<br />
cout << testo << endl << endl;<br />
}<br />
<br />
return 0;<br />
}</pre><br />
Stavolta che risultato vi aspettate di trovare?<br />
<br />
<br/>[[File:Qt III 16.png|Qt_III_16.png]]<br />
<br />
Beh, sembra proprio che il nostro compilatore abbia le sue simpatie: sceglie sempre la variabile più ‘locale’, ossia quella con lo spazio di visibilità più ristretto.<br />
<br />
<br/>Se la cosa vi sembra poco chiara, ripensiamo a ciò che abbiamo visto fin qui.<br />
<br />
#Una blocco di codice nel C++ è, come regola generale, un insieme di istruzioni che è contenuto fra parentesi graffe.<br />
#Una funzione è solo uno dei tanti tipi di blocchi di codice conosciuti.<br/>Altri tipi di blocchi di codice possono essere le istruzioni ''if'', i cicli ''for'' e ''while'', nonché altri che non abbiamo ancora visto.<br />
#I blocchi di codice possono essere contenuti uno dentro l’altro.<br />
#Lo ''scope'' di un blocco di codice finisce con la parentesi graffa chiusa.<br />
#Le variabili possono essere ''locali'' ai blocchi di codice, siano essi funzioni o altro (va bene, fino a qui non avevamo mai usato una variabile all’interno di un blocco ''if'', lo ammetto).<br />
#Le variabili globali sono pericolose perché possono essere modificate in qualsiasi punto del programma.<br />
<br />
Se mettiamo insieme quanto sopra, possiamo concludere che è ragionevole che il compilatore preferisca usare le variabili ''locali'', e che anzi, più ''locali'' sono, e più le preferisca.<br />
<br />
Perché mai dovrebbe partire dal presupposto che andremmo a complicarci la vita con quelle antipatiche delle variabili globali quando abbiamo a disposizione delle simpatiche variabili locali?<br />
<br />
<br/>Questa operazione, di prevalere sul nome globale, si chiama ''mascheramento''; ossia si dice che i nomi delle variabili locali ''mascherano'' (nascondono, oscurano, rendono inaccessibili) i nomi delle variabili globali. In inglese si parla di ''shadowing'' o ''hiding''.<br />
<br />
<br/>Questa è la regola generale, dopodiché ci sono una sacco di dettagli da ricordare:<br />
<br />
<br />
<br />
===== Variabili definite fra le parentesi tonde prima di un blocco di codice =====<br />
<br />
La regola generale è:<br />
<br />
'''è come se fossero state definite subito dopo la parentesi graffa con cui inizia il blocco'''.<br />
<br />
<br />
<br />
====== Il caso del parametro: ======<br />
<br />
Si è già detto che è identico a una variabile dichiarata all’inizio di una funzione, subito dopo la parentesi graffa aperta.<br />
<br />
Questa similitudine vale anche per la sua visibilità, che quindi vale per tutta la funzione, fino alla parentesi graffa chiusa. Pertanto il seguente codice è sbagliato:<br />
<pre>void unafunzione(int miopar)<br />
{<br />
int miopar; // errore! 'miopar' esiste già nel medesimo spazio di visibilità<br />
…<br />
}</pre><br />
Infatti il precedente codice è del tutto identico a questo (fatta eccezione per il fatto che ‘miopar’ riceve l’argomento inviato alla funzione):<br />
<pre>void unafunzione()<br />
{<br />
int miopar;<br />
int miopar; // errore! 'miopar' esiste già.<br />
…<br />
}</pre><br />
Invece il seguente codice sarebbe corretto:<br />
<pre>void unafunzione(int miopar)<br />
{<br />
if ( miopar == 3 ) {<br />
int miopar = 5;<br />
…<br />
}<br />
…</pre><br />
Tanto per verificare, l’output di questo programma:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
void unafunzione(int miopar);<br />
<br />
int main()<br />
{<br />
// I numeri usati in questo programma sono stati scelti<br />
// a caso e non hanno nessun significato particolare<br />
<br />
unafunzione(2);<br />
unafunzione(3);<br />
}<br />
<br />
void unafunzione(int miopar)<br />
{<br />
if ( miopar == 3 ) {<br />
int miopar = 5;<br />
cout << "miopar del blocco if == " << miopar << endl;<br />
}<br />
<br />
cout << "miopar globale == " << miopar << endl << endl;<br />
<br />
}</pre><br />
è questo:<br />
<br />
<br/>[[File:Qt III 17.png|Qt_III_17.png]]<br />
<br />
====== Il caso if, for, while e simili ======<br />
<br />
Se si crea una variabile fra le parentesi tonde di uno di questi blocchi, essa sarà visibile fino alla parentesi graffa alla fine del blocco.<br />
<br />
Il caso ''for'' è un classico:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
int numero = 0;<br />
<br />
for ( int numero = 1; numero < 6; numero++) {<br />
cout << "numero di for == " << numero << endl;<br />
}<br />
<br />
cout << "numero di main() == " << numero << endl << endl;<br />
}</pre><br />
<br />
<br/>[[File:Qt III 18.png|Qt_III_18.png]]<br />
<br />
<br />
<br />
====== Nel caso si voglia, fortissimamente voglia usare la variabile globale mascherata ======<br />
<br />
È possibile anche questo. Il C++ è davvero un linguaggio curato.<br />
<br />
Esiste un simbolo apposta, che si chiama ''operatore di scope resolution'', che può essere usato anche a questo scopo (di solito è usato in altre occasioni). Il simbolo è il seguente&nbsp;: ‘::’.<br />
<br />
Sì, sono due doppi punti uno di seguito all’altro. Va scritto subito prima del nome della variabile.<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
string testo = "Sono una variabile GLOBALE";<br />
<br />
int main()<br />
{<br />
string testo = "Sono una variabile LOCALE";<br />
<br />
if (true) {<br />
string testo = "Sono una variabile in un BLOCCO IF";<br />
cout << "Sorpresa! Posso usare la variabile globale da qui&nbsp;:)" << endl;<br />
cout << "testo == " <<&nbsp;::testo << endl << endl;<br />
}<br />
<br />
}</pre><br />
<br/>[[File:Qt III 19.png|Qt_III_19.png]]<br />
<br />
Attenzione! Il simbolo ‘::’ non può essere usato per… “tornare su di un livello”. Lui va a cercare la variabile globale, '''se esiste''', non quella del blocco più esterno (cosa confermata dall’output precedente).<br />
<br />
<br/>'''Non c’è un modo per utilizzare una variabile locale che sia stata mascherata finché non si esce dal blocco in cui esiste la variabile che maschera.'''<br />
<br />
====== Un esempio… perverso&nbsp;:) ======<br />
<br />
Domanda: qual è il punto in cui inizia il mascheramento? Quando si apre il blocco di codice dov’è contenuta la variabile che maschera, oppure quando si incontra la definizione della variabile che maschera?<br />
<br />
<br/>Beh, per rispondere questo dubbio amletico riporto qui un esempio del sig. Stroupstrup in persona, tratto dalla versione italiana del suo libro ''The C++ Programming Language – Second Edition''. Anche il codice esemplificativo è suo, nonché il commento.<br />
<blockquote>Un nome risulta visibile a partire dal punto di dichiarazione […]; ciò significa che un nome può essere usato anche per specificare il suo valore iniziale. Ad esempio:<pre>int x;<br />
<br />
void f3()<br />
{<br />
int x = x; // perverse<br />
}</pre></blockquote><br />
<br/>A questo punto non vi resta che inventare un codice per mettere alla prova questa affermazione dell’inventore del C++. Con questo esercizio lasciamo l’argomento perché gli oggetti ci reclamano a gran voce.<br />
<br />
Alla prossima puntata!<br />
[[Category:C++|Category:C++]]</div>
Robi
https://kata.coderdojo.it/wiki/index.php?title=Framework_per_gioco_a_bivi
Framework per gioco a bivi
2014-11-30T15:47:27Z
<p>Robi: Aggiunta categoria JavaScrpt</p>
<hr />
<div>File index.html:<br />
<pre><!DOCTYPE html><br />
<html lang="it"><br />
<head><br />
<meta charset="utf-8"><br />
<br />
<meta name="description" content=""><br />
<meta name="author" content="Roberto Naldi"><br />
<br />
<link rel="stylesheet" type="text/css" href="jsframe01.css" /><br />
<br />
<title>Inizio</title><br />
</head><br />
<br />
<body onload="settaggiBase();"><br />
<div><br />
<header><br />
<h1>CoderDojo Firenze</h1><br />
</header><br />
<br />
<section id="sezStoria"><br />
<h1 id="titolo">&nbsp;</h1><br />
<br />
<p id="descrizione">&nbsp;</p><br />
<br />
<section id="scelte"><br />
<p><a href="#scelta1" id="scelta1" onclick="raggiungiLuogo(this);">nbsp;</a></p><br />
<p><a href="#scelta2" id="scelta2" onclick="raggiungiLuogo(this);">nbsp;</a></p><br />
</section><br />
</section><br />
<br />
<section id="sezComandi"><br />
<h1>Crea la tua storia!</h1><br />
<form><br />
<fieldset><br />
<legend>Usa questi campi per aggiungere nuove situazioni</legend><br />
<div><br />
<label>Un titolo per questa situazione:</label><br />
<input type="text" placeholder="Es. La Sala del Tesoro" id="nuovoTitolo" /><br />
</div><br />
<div><br />
<label>Descrivi cosa c’è e cosa succede:</label><br />
<textarea cols="60" rows="10" placeholder="Ti trovi in un grande..." id="nuovaDescri"></textarea><br />
</div><br />
<div class="bordato"><br />
<p>Se non è il finale, dovrai offrire almeno un’azione da compiere; sarebbero meglio due.</p><br />
<div><br />
<label>Descrivi qui la prima scelta:</label><br />
<input type="text" placeholder="Esco dalla porta..." id="nuovaScelta1" /><br />
</div><br />
<div><br />
<label>Scrivi il nome della situazione in cui si andrà a finire:</label><br />
<input type="text" placeholder="es. ScalaRipida" id="nuovoLuogo1" class="corto" /><br />
</div><br />
<hr /><br />
<div><br />
<label>Descrivi qui la seconda scelta:</label><br />
<input type="text" placeholder="Passo dalla finestra..." id="nuovaScelta2" class="corto" /><br />
</div><br />
<div><br />
<label>Scrivi il nome della situazione in cui si andrà a finire:</label><br />
<input type="text" placeholder="es. Terrazza" id="nuovoLuogo2" class="corto" /><br />
</div><br />
</div><br />
<div><br />
<p class="centrato grassetto grande">Attenzione! Il primo nome deve essere “Inizio”!</p><br />
<label>Il nome che il pc userà per ritrovare questa situazione:</label><br />
<input type="text" placeholder="es. StanzaBlu" id="nuovoNome" class="corto" /><br />
</div><br />
<div><br />
<label>Per caricare in memoria clicka qui:</label><br />
<input type="button" value="Registra" class="corto" onclick="registraLuogo();" /><br />
</div><br />
</fieldset><br />
<div><br />
<label>Quando hai finito clicka qui:</label><br />
<input type="button" value="Dammi lista" class="corto" onclick="listaDaCopiare();" /><br />
</div><br />
</form><br />
</section><br />
<br />
<section id="sezDaCopiare">&nbsp;</section><br />
<br />
<footer><br />
<p>© Copyright by Coder Dojo Firenze</p><br />
</footer><br />
</div><br />
<script type="text/javascript" src="fm01.js"></script><br />
<script type="text/javascript" src="settaggi.js"></script><br />
</body><br />
</html><br />
<br />
</pre><br />
File fm01.js<br />
<pre>/*--------------------------------------------------------------<br />
* VARIABILI GLOBALI<br />
-------------------------------------------------------------*/<br />
<br />
/*<br />
* Contenitore di tutti i luoghi esistenti<br />
*/<br />
var luoghi = {};<br />
<br />
/*<br />
* Contenitore per i luoghi che saranno creati<br />
*/<br />
var nuoviLuoghi = {};<br />
<br />
/*<br />
* Connessioni 'permanenti' ad elementi HTML<br />
* Le seguenti variabili servono per ridurre le chiamate <br />
* a document.getElementById<br />
*/<br />
var htmlTitolo = document.getElementById("titolo");<br />
var htmlDescrizione = document.getElementById("descrizione");<br />
var htmlScelta1 = document.getElementById("scelta1");<br />
var htmlScelta2 = document.getElementById("scelta2");<br />
var htmlNuovoNome = document.getElementById("nuovoNome");<br />
var htmlNuovoTitolo = document.getElementById("nuovoTitolo");<br />
var htmlNuovaDescrizione = document.getElementById("nuovaDescri");<br />
var htmlNuovaScelta1Des = document.getElementById("nuovaScelta1");<br />
var htmlNuovaScelta1Nome = document.getElementById("nuovoLuogo1");<br />
var htmlNuovaScelta2Des = document.getElementById("nuovaScelta2");<br />
var htmlNuovaScelta2Nome = document.getElementById("nuovoLuogo2");<br />
<br />
// la seguente variabile tiene traccia del luogo dove siamo<br />
// in questo momento<br />
var gloPosizione;<br />
<br />
<br />
/*--------------------------------------------------------------<br />
* Oggetto base che rappresenta un luogo<br />
* <br />
* Un 'luogo' rappresenta il nucleo della narrazione. <br />
-------------------------------------------------------------*/<br />
// Creo il costruttore di luogo<br />
function luogo(nome, titolo, descrizione)<br />
{<br />
// Proprieta'<br />
this.luogoNome = nome; // nome sara' usato per identificare il luogo<br />
this.luogoTitolo = titolo;<br />
this.luogoDescrizione = descrizione;<br />
this.alternative = {<br />
vaiA1&nbsp;: { testo&nbsp;: "testo a schermo", posto&nbsp;: "PrimaScelta"},<br />
vaiA2&nbsp;: { testo&nbsp;: "testo a schermo", posto&nbsp;: "SecondaScelta"}<br />
};<br />
}<br />
<br />
<br />
<br />
/*--------------------------------------------------------------<br />
* settaggiBase() inizializza gli oggetti<br />
* <br />
-------------------------------------------------------------*/<br />
function settaggiBase() {<br />
elencaLuoghi();<br />
gloPosizione = luoghi["Inizio"];<br />
storiaASchermo();<br />
}<br />
<br />
function raggiungiLuogo(partenza) {<br />
var tmpPosizione;<br />
<br />
// Il valore di 'partenza' a questo punto è simile a:<br />
// file:///C:/...index.html#scelta1<br />
// A noi ci servono gli ultimi 7 caratteri (scelta1/2)<br />
// Quindi, 7imo carattere prima della fine, una string di 7 caratteri<br />
partenza = partenza.toString();<br />
partenza = partenza.substr(partenza.length - 7, 7);<br />
<br />
switch(partenza) {<br />
case "scelta1":<br />
tmpPosizione = gloPosizione.alternative.vaiA1.posto;<br />
break;<br />
case "scelta2": <br />
tmpPosizione = gloPosizione.alternative.vaiA2.posto;<br />
break;<br />
default:<br />
alert("Errore nel programma!\nFunzione raggiungiLuogo\nIstruzione switch\nPartenza = " + partenza);<br />
return;<br />
}<br />
<br />
gloPosizione = luoghi[tmpPosizione];<br />
storiaASchermo();<br />
}<br />
<br />
<br />
<br />
function storiaASchermo () {<br />
htmlTitolo.innerHTML = gloPosizione.luogoTitolo;<br />
htmlDescrizione.innerHTML = gloPosizione.luogoDescrizione;<br />
htmlScelta1.innerHTML = gloPosizione.alternative.vaiA1.testo;<br />
htmlScelta2.innerHTML = gloPosizione.alternative.vaiA2.testo;<br />
}<br />
<br />
<br />
<br />
function caricaLuoghi(name, tit, descr, a1_testo, a1_luogo, a2_testo, a2_luogo) {<br />
var tmpLuogo = new luogo;<br />
<br />
tmpLuogo.luogoNome = name;<br />
tmpLuogo.luogoTitolo = tit;<br />
tmpLuogo.luogoDescrizione = descr;<br />
tmpLuogo.alternative.vaiA1.testo = a1_testo;<br />
tmpLuogo.alternative.vaiA1.posto = a1_luogo;<br />
tmpLuogo.alternative.vaiA2.testo = a2_testo;<br />
tmpLuogo.alternative.vaiA2.posto = a2_luogo;<br />
<br />
luoghi[tmpLuogo.luogoNome] = tmpLuogo;<br />
}<br />
<br />
<br />
function registraLuogo() {<br />
var tmpLuogo = new luogo;<br />
<br />
tmpLuogo.luogoNome = htmlNuovoNome.value;<br />
tmpLuogo.luogoTitolo = htmlNuovoTitolo.value;<br />
tmpLuogo.luogoDescrizione = htmlNuovaDescrizione.value;<br />
tmpLuogo.alternative.vaiA1.testo = htmlNuovaScelta1Des.value;<br />
tmpLuogo.alternative.vaiA1.posto = htmlNuovaScelta1Nome.value;<br />
tmpLuogo.alternative.vaiA2.testo = htmlNuovaScelta2Des.value;<br />
tmpLuogo.alternative.vaiA2.posto = htmlNuovaScelta2Nome.value;<br />
<br />
nuoviLuoghi[tmpLuogo.luogoNome] = tmpLuogo;<br />
<br />
htmlNuovoNome.value = "";<br />
htmlNuovoTitolo.value = "";<br />
htmlNuovaDescrizione.value = "";<br />
htmlNuovaScelta1Des.value = "";<br />
htmlNuovaScelta1Nome.value = "";<br />
htmlNuovaScelta2Des.value = "";<br />
htmlNuovaScelta2Nome.value = "";<br />
}<br />
<br />
<br />
function listaDaCopiare() {<br />
//alert("listaDaCopiare()");<br />
inizioListaDaCopiare();<br />
var rifSezDaCopiare = document.getElementById("sezDaCopiare");<br />
<br />
for(var indice in nuoviLuoghi) {<br />
if (nuoviLuoghi.hasOwnProperty(indice)) {<br />
var elemento = nuoviLuoghi[indice];<br />
<br />
var pNome = document.createElement("p");<br />
var tnNome = document.createTextNode('var nome = "' + elemento.luogoNome + '";');<br />
pNome.appendChild(tnNome);<br />
<br />
var pTitolo = document.createElement("p");<br />
var tnTitolo = document.createTextNode('var titolo = "' + elemento.luogoTitolo + '";');<br />
pTitolo.appendChild(tnTitolo);<br />
<br />
var pDescrizione = document.createElement("p");<br />
var tnDescrizione = document.createTextNode('var descrizione = "' + elemento.luogoDescrizione + '";');<br />
pDescrizione.appendChild(tnDescrizione);<br />
<br />
var pVaiA1_testo = document.createElement("p");<br />
var tnVaiA1_testo = document.createTextNode('var vaiA1_testo = "' + elemento.alternative.vaiA1.testo + '";');<br />
pVaiA1_testo.appendChild(tnVaiA1_testo);<br />
<br />
var pVaiA1_luogo = document.createElement("p");<br />
var tnVaiA1_luogo = document.createTextNode('var vaiA1_luogo = "' + elemento.alternative.vaiA1.posto + '";');<br />
pVaiA1_luogo.appendChild(tnVaiA1_luogo);<br />
<br />
var pVaiA2_testo = document.createElement("p");<br />
var tnVaiA2_testo = document.createTextNode('var vaiA2_testo = "' + elemento.alternative.vaiA2.testo + '";');<br />
pVaiA2_testo.appendChild(tnVaiA2_testo);<br />
<br />
var pVaiA2_luogo = document.createElement("p");<br />
var tnVaiA2_luogo = document.createTextNode('var vaiA2_luogo = "' + elemento.alternative.vaiA2.posto + '";');<br />
pVaiA2_luogo.appendChild(tnVaiA2_luogo);<br />
<br />
var pCaricaLuoghi = document.createElement("p");<br />
var tnCaricaLuoghi = document.createTextNode('caricaLuoghi(nome, titolo, descrizione, vaiA1_testo, vaiA1_luogo, vaiA2_testo, vaiA2_luogo);');<br />
pCaricaLuoghi.appendChild(tnCaricaLuoghi);<br />
<br />
rifSezDaCopiare.appendChild(pNome);<br />
rifSezDaCopiare.appendChild(pTitolo);<br />
rifSezDaCopiare.appendChild(pDescrizione);<br />
rifSezDaCopiare.appendChild(pVaiA1_testo);<br />
rifSezDaCopiare.appendChild(pVaiA1_luogo);<br />
rifSezDaCopiare.appendChild(pVaiA2_testo);<br />
rifSezDaCopiare.appendChild(pVaiA2_luogo);<br />
rifSezDaCopiare.appendChild(pCaricaLuoghi);<br />
<br />
}<br />
}<br />
<br />
var pGraffaFinale = document.createElement("p");<br />
var tnGraffaFinale = document.createTextNode("}");<br />
pGraffaFinale.appendChild(tnGraffaFinale);<br />
rifSezDaCopiare.appendChild(pGraffaFinale);<br />
}<br />
<br />
<br />
function inizioListaDaCopiare () {<br />
// La prima parte della lista deve essere<br />
// function elencaLuoghi() {<br />
var pEleLuoghi = document.createElement("p");<br />
var tnEleLuoghi = document.createTextNode("function elencaLuoghi() {");<br />
pEleLuoghi.appendChild(tnEleLuoghi);<br />
<br />
// a questo punto si può decidere se costringere ad un inizio<br />
// standard oppure no.<br />
// Il primo luogo si deve chiamare "Inizio"<br />
// con la 'I' maiuscola<br />
<br />
/*var pNome = document.createElement("p");<br />
var tnNome = document.createTextNode('var nome = "Inizio";');<br />
pNome.appendChild(tnNome);<br />
<br />
var pTitolo = document.createElement("p");<br />
var tnTitolo = document.createTextNode('var titolo = "Il gioco dei bivi";');<br />
pTitolo.appendChild(tnTitolo);<br />
<br />
var pDescrizione = document.createElement("p");<br />
var tnDescrizione = document.createTextNode('var descrizione = "Stai per iniziare un’avventura scritta da qualcuno della tua età!";');<br />
pDescrizione.appendChild(tnDescrizione);<br />
<br />
var pVaiA1_testo = document.createElement("p");<br />
var tnVaiA1_testo = document.createTextNode('var vaiA1_testo = "Inizia";');<br />
pVaiA1_testo.appendChild(tnVaiA1_testo);<br />
<br />
var pVaiA1_luogo = document.createElement("p");<br />
var tnVaiA1_luogo = document.createTextNode('var vaiA1_luogo = "InizioGioco";');<br />
pVaiA1_luogo.appendChild(tnVaiA1_luogo);<br />
<br />
var pVaiA2_testo = document.createElement("p");<br />
var tnVaiA2_testo = document.createTextNode('var vaiA2_testo = "Rinuncia";');<br />
pVaiA2_testo.appendChild(tnVaiA2_testo);<br />
<br />
var pVaiA2_luogo = document.createElement("p");<br />
var tnVaiA2_luogo = document.createTextNode('var vaiA2_luogo = "FineGioco";');<br />
pVaiA2_luogo.appendChild(tnVaiA2_luogo);<br />
<br />
var pCaricaLuoghi = document.createElement("p");<br />
var tnCaricaLuoghi = document.createTextNode('caricaLuoghi(nome, titolo, descrizione, vaiA1_testo, vaiA1_luogo, vaiA2_testo, vaiA2_luogo);');<br />
pCaricaLuoghi.appendChild(tnCaricaLuoghi);*/<br />
<br />
var rifSezDaCopiare = document.getElementById("sezDaCopiare");<br />
rifSezDaCopiare.appendChild(pEleLuoghi);<br />
/*rifSezDaCopiare.appendChild(pNome);<br />
rifSezDaCopiare.appendChild(pTitolo);<br />
rifSezDaCopiare.appendChild(pDescrizione);<br />
rifSezDaCopiare.appendChild(pVaiA1_testo);<br />
rifSezDaCopiare.appendChild(pVaiA1_luogo);<br />
rifSezDaCopiare.appendChild(pVaiA2_testo);<br />
rifSezDaCopiare.appendChild(pVaiA2_luogo);<br />
rifSezDaCopiare.appendChild(pCaricaLuoghi);*/<br />
}<br />
<br />
<br />
<br />
<br />
// Funzione per conoscere le dimensioni di un oggetto JavaScript<br />
function dimOggetto(oggetto) {<br />
var contatore = 0;<br />
<br />
if (typeof oggetto == "object") {<br />
<br />
if (Object.keys) {<br />
contatore = Object.keys(oggetto).length;<br />
} else if (window._) {<br />
contatore = _.keys(oggetto).length;<br />
} else if (window.$) {<br />
contatore = $.map(oggetto, function() { return 1; }).length;<br />
} else {<br />
for (var key in oggetto) if (oggetto.hasOwnProperty(key)) contatore++;<br />
}<br />
<br />
}<br />
<br />
return contatore;<br />
}<br />
<br />
</pre><br />
<br/>File settaggi.js<br />
<pre>function elencaLuoghi() {<br />
var nome = "Inizio";<br />
var titolo = "Il gioco dei bivi";<br />
var descrizione = "Stai per iniziare un’avventura scritta da qualcuno della tua età!";<br />
var vaiA1_testo = "Inizia";<br />
var vaiA1_luogo = "InizioGioco";<br />
var vaiA2_testo = "Rinuncia";<br />
var vaiA2_luogo = "FineGioco";<br />
<br />
caricaLuoghi(nome, titolo, descrizione, vaiA1_testo, vaiA1_luogo, vaiA2_testo, vaiA2_luogo);<br />
<br />
nome = "InizioGioco";<br />
titolo = "Il Castello Maledetto";<br />
descrizione = "Ti trovi fuori da un castello dall’aspetto tetro.<br />Davanti a te c’è un ponte levatoio del tutto allo scoperto.<br />Sotto di te un fossato pieno d'acqua.<br />Cosa fai?";<br />
vaiA1_testo = "Attraverso il ponte levatoio";<br />
vaiA1_luogo = "PuntoMorto";<br />
vaiA2_testo = "Mi tuffo nel fossato";<br />
vaiA2_luogo = "PuntoMorto";<br />
<br />
caricaLuoghi(nome, titolo, descrizione, vaiA1_testo, vaiA1_luogo, vaiA2_testo, vaiA2_luogo);<br />
<br />
nome = "FineGioco";<br />
titolo = "Il Castello Maledetto";<br />
descrizione = "Peccato! Speravo tanto tu ci volessi giocare...<br />Ora cosa farai?";<br />
vaiA1_testo = "Spengo il computer e vado a nanna.";<br />
vaiA1_luogo = "PuntoMorto";<br />
vaiA2_testo = "Imparo qualcos’altro.";<br />
vaiA2_luogo = "PuntoMorto";<br />
<br />
caricaLuoghi(nome, titolo, descrizione, vaiA1_testo, vaiA1_luogo, vaiA2_testo, vaiA2_luogo);<br />
}<br />
<br />
</pre><br />
<br/><br/>File jsframe01.css:<br />
<pre>body {<br />
background-color: #E6E6E6;<br />
}<br />
<br />
header {<br />
background-color: teal;<br />
color: yellow;<br />
margin-bottom: 3em;<br />
}<br />
<br />
header h1 {<br />
margin-left: 0;<br />
text-align: center;<br />
}<br />
<br />
footer {<br />
background-color: blue;<br />
color: yellow;<br />
margin-top: 2em;<br />
}<br />
<br />
footer p {<br />
margin-left: 0;<br />
text-align: center;<br />
}<br />
<br />
fieldset > div {<br />
margin-top: 1em;<br />
}<br />
<br />
fieldset > div > div {<br />
margin-top: 0.5em;<br />
}<br />
<br />
hr {<br />
margin: 1em 30%;<br />
}<br />
<br />
input {<br />
width: 25em;<br />
}<br />
<br />
input.corto {<br />
width: auto;<br />
}<br />
<br />
#sezStoria {<br />
border-style: ridge;<br />
margin: auto 20%;<br />
padding: 1em;<br />
}<br />
<br />
#sezComandi {<br />
border-style: ridge;<br />
margin: auto 20%;<br />
padding: 1em;<br />
}<br />
<br />
#sezDaCopiare {<br />
margin-top: 2em;<br />
background-color: #FFFFCC;<br />
}<br />
<br />
#sezDaCopiare p{<br />
margin: 0 auto;<br />
}<br />
<br />
.centrato {<br />
margin-left: 0;<br />
text-align: center;<br />
}<br />
<br />
.bordato {<br />
border-style: ridge;<br />
padding: 0.5em;<br />
}<br />
<br />
.grassetto {<br />
font-weight: bold;<br />
}<br />
<br />
.grande {<br />
font-size: large;<br />
}<br />
<br />
<br />
</pre><br />
[[Category:Javascript]]</div>
Robi
https://kata.coderdojo.it/wiki/index.php?title=Tutorial_C%2B%2B_con_Qt_-_Parte_II
Tutorial C++ con Qt - Parte II
2014-11-12T16:19:15Z
<p>Robi: Corretto errore logico della condizione while che consentiva di prendere 5 fiammiferi</p>
<hr />
<div>= Tutorial C++ con le librerie Qt – Parte II =<br />
<br />
== Come superare gli schieramenti ==<br />
<br />
=== Se uno ha troppi amici… ===<br />
<br />
Ripartiamo da dov’eravamo rimasti.<br />
<br />
Vorrei che provaste a confrontare queste due righe di codice:<br />
<br />
Nella funzione ''salutaUtente'':<br />
<pre>segnale_di_ritorno = -1;</pre><br />
Nella funzione interrogaUtente:<br />
<pre>if ( verifica == -1 ) {</pre><br />
A parte le varie parentesi, tonda e graffa, ci vedete qualche differenza?<br />
<br />
Vi salta all’occhio lo strano simbolo ‘==’?<br />
<br />
Visto che esiste l’equivalente in JavaScript (e anche in C, tanto per cambiare), adesso vedremo cosa significa in quel linguaggio. Però diamo prima un’occhiata a questo codice Scratch, che ci aprirà un po’ la strada:<br />
<br />
<br/>[[File:C++ Qt 02 Scratch 01.png|C++ con Qt, parte II, Scratch 01]]<br />
<br />
Okay, apparentemente non c’entra nulla, ma ci serve un po’ di pazienza.<br />
<br />
Questo esempio è piuttosto semplice, ma introduce un po’ una complicazione: un’istruzione SE contenuta dentro un’altra.<br />
<br />
Proviamo a esprimere a parole le istruzioni di questo programma, proprio come se stessimo parlando a un robottino e gli dovessimo spiegare passo passo cosa fare:<br />
<br />
Quando faccio click, tu (robottino) memorizza questi due dati: Mario e Maria in due celle di memoria, amico1 e amico2; poi chiedi a chi si avvicina: “Come ti chiami?”. Dopo procedi così:<br />
<br />
*se la risposta che ti hanno dato è uguale a quello che hai scritto nella variabile amico1, allora saluta;<br />
*altrimenti (quindi, se la risposta non è uguale a quello che è scritto in amico1), confronta la risposta con quello che è scritto in amico2; se stavolta è uguale, saluta;<br />
*altrimenti, digli che non lo conosci.<br />
<br />
<br/>Wow! Faticoso, non è vero? Mi accorgo ora che ho messo un’istruzione di troppo: l’istruzione ''porta nome a risposta'' si può tranquillamente ignorare. Ma, a parte quella, direi che la vita del robottino è un po’ complicata.<br />
<br />
Pensate un po’ se voleste istruirlo a riconoscere 4 amici, anziché 2. Guardate un po’ come verrebbe:<br />
<br />
<br/>[[File:C++ Qt 02 Scratch 02.png|C++ con Qt, parte II, Scratch 02]]<br />
<br />
Anche qui c’è un’istruzione di troppo, la stessa di prima, ma non è quella che ci sta complicando la vita. La domanda è: come verrebbe il programma se il robottino dovesse imparare a salutare '''tutti''' i vostri compagni di classe o tutte le persone che conoscete?<br />
<br />
Chi ci capirebbe più niente, in tutti quei SE… ALLORA… ALTRIMENTI?<br />
<br />
<br/>Per fortuna il robottino è furbo e ci suggerisce un’alternativa:<br />
<br />
<br/>[[File:C++ Qt 02 Scratch 03.png|C++ con Qt, parte II, Scratch 03]]<br />
<br />
Questo esempio fa la stessa cosa del precedente, ma introduce una cosa nuova, che fin qui non avevamo trattato: le liste.<br />
<br />
Cos’è una lista?<br />
<br />
Pensiamo ai compiti da fare a casa: il maestro/a o professore/essa ci danno una serie di cose da studiare o di esercizi da fare. Certo, possono essere tutti diversi fra di loro, tipo leggere e ripetere pagine di storia; oppure condurre l’analisi logica di alcune frasi; oppure risolvere problemi di matematica; o molte altre cose. Però, anche se sono tutte diverse, per noi rientrano in un’unica categoria: sono i compiti per casa.<br />
<br />
<br/>Tant’è che sul diario li scriviamo tutti insieme: a quella determinata data scriviamo tutte le materie che dobbiamo avere studiato, siano esse storia o italiano o matematica.<br />
<br />
Altri esempi simili possono essere la lista della spesa o la rubrica del telefono: in una sono segnati oggetti che sono diversissimi fra di loro, come la verdura e i detersivi, mentre nella seconda ci possono essere nomi anche di persone che non si conoscono l’un con l’altra.<br />
<br />
<br/>Ma tutte queste cose hanno qualcosa in comune, che è il motivo per cui le scriviamo tutte di seguito, una dietro l’altra:<br />
<br />
*i compiti hanno in comune la data in cui devono essere svolti;<br />
*i nomi nella rubrica hanno in comune di essere nostri amici o parenti;<br />
*gli oggetti nella lista della spesa hanno in comune di dover essere tutti acquistati oggi.<br />
<br />
Quindi: quando una serie di cose, simili o dissimili fra di loro, hanno un punto in comune, di solito preferiamo non considerarle come tante cose singole, ma come un’unica lista di tante cose.<br />
<br />
<br/>Anche quando creiamo una variabile possiamo pensare di doverci mettere un dato singolo, che non ha nessun rapporto con il contenuto delle altre variabili, oppure di doverci mettere una serie di dati che hanno qualcosa in comune.<br />
<br />
<br/>Nell’esempio Scratch precedente abbiamo deciso che non aveva senso creare una serie di variabili “amico1”, “amico2”, “amico3”… Abbiamo invece preferito creare un’unica lista “Amici” in cui ci fosse posto per tutti.<br />
<br />
<br/>Sono contento che abbiamo avuto modo di parlare di questo perché anche nel JavaScript e nel C++ abbiamo delle cose simile alle liste, ma si chiamano array, che è una parola inglese che significa ''schieramento'', oppure ''varietà'', ''gamma'' di oggetti. Come sapete, le parole ogni tanto hanno più significati e delle volte anche distanti fra di loro.<br />
<br />
<br/>Però dobbiamo rimandare di un pochino il momento in cui affronteremo gli array in JavaScript perché ci eravamo ripromessi di guardare il significato del doppio simbolo di uguale, quella strana scritta ‘==’ che abbiamo trovato nel nostro programma.<br />
<br />
<br/>Partiamo dal JavaScript:<br />
<pre><!DOCTYPE html><br />
<br />
<html lang="it-IT"><br />
<head><br />
<meta charset="utf-8"><br />
<br />
<title>JavaScript e HTML5 - un pulsante che saluta... a volte!</title><br />
<br />
<script type="text/javascript"><br />
function cambioTesto() {<br />
var utente = document.getElementById("risposta").value;<br />
<br />
if ( 1 == controllaNome(utente) ) {<br />
document.getElementById("testoDaCambiare").innerHTML = "Ciao, " + utente + "!";<br />
}<br />
else {<br />
document.getElementById("testoDaCambiare").innerHTML = "Non ti conosco, " + utente + "!";<br />
}<br />
<br />
}<br />
<br />
function controllaNome(persona) {<br />
<br />
var risultato;<br />
<br />
if (persona == "Mario" || persona == "Maria" <br />
|| persona == "Gianni" || persona == "Gianna") {<br />
risultato = 1;<br />
}<br />
else {<br />
risultato = 0;<br />
}<br />
<br />
return risultato;<br />
}<br />
</script><br />
<br />
<style><br />
.fraseCattiva {<br />
color&nbsp;: red;<br />
text-decoration&nbsp;: underline;<br />
text-transform&nbsp;: uppercase;<br />
}<br />
</style><br />
</head><br />
<br />
<body><br />
<br />
<div><br />
<p>Sappi che oggi sono d'umore un po’ scontroso. Può darsi che ti saluti e può darsi di <span class="fraseCattiva">no</span>.</p><br />
<p>Tu comunque provaci lo stesso…</p><br />
</div><br />
<br />
<div><br />
<label for="risposta">Qual è il tuo nome?</label><br />
<input type="text" id="risposta" /><br />
</div><br />
<br />
<div><br />
<label for="cambiaTesto">Pulsante che modificherà il testo sottostante --></label><br />
<input type="button" id="cambiaTesto" value="Premimi per cambiare il testo"<br />
onclick="cambioTesto();" /><br />
</div><br />
<br />
<div><br />
<p id="testoDaCambiare">Il testo contenuto in questo paragrafo cambierà quando sarà premuto il pulsante soprastante.</p><br />
</div><br />
<br />
</body><br />
</html><br />
</pre><br />
Come primo commento lasciatemi dire: che brutto!<br />
<br />
Lo so che ora stavamo parlando d’altro, e fra un attimo riprendo il filo, però prima o poi a questa osservazione bisognava arrivarci: adesso abbiamo un codice dove si trovano mischiati HTML5, JavaScript e CSS. Non ci si capisce più niente. Se vogliamo avventurarci nel mondo del C++ dobbiamo essere molto più precisi, perché nel C++ il codice deve stare diviso in blocchi coerenti.<br />
<br />
<br/>Cominciamo da questo: entriamo in una cartella dove possiamo salvare i nostri file che non sono C++ – oppure creiamone una.<br />
<br />
Poi facciamo il copia-incolla del codice di cui sopra e chiamiamolo BruttaRisposta.html<br />
<br />
Fin qui non ci dovrebbero essere novità. Ora però creiamo altri due file, vuoti:<br />
<br />
*BruttaRisposta.js<br />
*BruttaRisposta.CSS<br />
<br />
Tagliamo dal file BruttaRisposta.html le righe<br />
<pre> function cambioTesto(){<br />
var utente = document.getElementById("risposta").value;<br />
<br />
if ( 1 == controllaNome(utente) ) {<br />
document.getElementById("testoDaCambiare").innerHTML = "Ciao, " + utente + "!";<br />
}<br />
else {<br />
document.getElementById("testoDaCambiare").innerHTML = "Non ti conosco, " + utente + "!";<br />
}<br />
<br />
}<br />
<br />
function controllaNome(persona) {<br />
<br />
var risultato;<br />
<br />
if (persona == "Mario" || persona == "Maria" <br />
|| persona == "Gianni" || persona == "Gianna") {<br />
risultato = 1;<br />
}<br />
else{<br />
risultato = 0;<br />
}<br />
<br />
return risultato;<br />
}<br />
</pre><br />
e incolliamole nel file BruttaRisposta.js.<br />
<br />
<br/>Nel file BruttaRisposta.html modifichiamo le righe:<br />
<pre><script type="text/javascript"><br />
</script><br />
</pre><br />
in questo modo:<br />
<pre><script type="text/javascript" src="BruttaRisposta.js"></script></pre><br />
Dallo stesso file facciamo il taglia delle seguenti righe:<br />
<pre> .fraseCattiva {<br />
color &nbsp;: red;<br />
text-decoration&nbsp;: underline;<br />
text-transform &nbsp;: uppercase;<br />
}<br />
</pre><br />
e incolliamole nel file BruttaRisposta.CSS<br />
<br />
Sempre nel file BruttaRisposta.html, '''modifichiamo''' le seguenti righe:<br />
<pre> <style><br />
</style><br />
</pre><br />
in modo che diventino così:<br />
<pre> <link rel="stylesheet" href="BruttaRisposta.CSS" type="text/css" /></pre><br />
(di due righe ne rimane una)<br />
<br />
<br/>A questo punto dovremmo trovarci in questa situazione:<br />
<br />
<br/>Un file BruttaRisposta.html con questo codice dentro:<br />
<pre><!DOCTYPE html><br />
<br />
<html lang="it-IT"><br />
<head><br />
<meta charset="utf-8"><br />
<br />
<title>JavaScript e HTML5 - un pulsante che saluta... a volte!</title><br />
<br />
<script type="text/javascript" src="BruttaRisposta.js"></script><br />
<br />
<link rel="stylesheet" href="BruttaRisposta.CSS" type="text/css" /><br />
</head><br />
<br />
<body><br />
<br />
<div><br />
<p>Sappi che oggi sono d'umore un po’ scontroso. Può darsi che ti saluti e può darsi di <span class="fraseCattiva">no</span>.</p><br />
<p>Tu comunque provaci lo stesso…</p><br />
</div><br />
<br />
<div><br />
<label for="risposta">Qual è il tuo nome?</label><br />
<input type="text" id="risposta" /><br />
</div><br />
<br />
<div><br />
<label for="cambiaTesto">Pulsante che modificherà il testo sottostante --></label><br />
<input type="button" id="cambiaTesto" value="Premimi per cambiare il testo"<br />
onclick="cambioTesto();" /><br />
</div><br />
<br />
<div><br />
<p id="testoDaCambiare">Il testo contenuto in questo paragrafo cambierà quando sarà premuto il pulsante soprastante.</p><br />
</div><br />
<br />
</body><br />
</html><br />
</pre><br />
Un file BruttaRisposta.js con questo codice dentro:<br />
<pre>function cambioTesto() {<br />
var utente = document.getElementById("risposta").value;<br />
<br />
if ( 1 == controllaNome(utente) ) {<br />
document.getElementById("testoDaCambiare").innerHTML = "Ciao, " + utente + "!";<br />
}<br />
else {<br />
document.getElementById("testoDaCambiare").innerHTML = "Non ti conosco, " + utente + "!";<br />
}<br />
<br />
}<br />
<br />
function controllaNome(persona) {<br />
var risultato;<br />
<br />
if (persona == "Mario" || persona == "Maria" <br />
|| persona == "Gianni" || persona == "Gianna") {<br />
risultato = 1;<br />
}<br />
else {<br />
risultato = 0;<br />
}<br />
<br />
return risultato;<br />
}<br />
</pre><br />
Un file BruttaRisposta.CSS con questo codice dentro:<br />
<pre>.fraseCattiva {<br />
color&nbsp;: red;<br />
text-decoration&nbsp;: underline;<br />
text-transform&nbsp;: uppercase;<br />
}<br />
</pre><br />
I tre file sembrano separati fra di loro, ma non lo sono: finché li avremo tutti e tre nella stessa cartella, le nuove istruzioni nel file HTML porteranno il browser a caricare tutti e tre i file e ad usarli come se fossero tutti scritti nello stesso file.<br />
<br />
<br/>Ossia, quando il browser leggerà:<br />
<pre><script type="text/javascript" src="BruttaRisposta.js"></script></pre><br />
andrà a cercare il file BruttaRisposta.js e lo caricherà in memoria per intero, e solo dopo che avrà finito questa operazione proseguirà a leggere il resto del documento HTML.<br />
<br />
Lo stesso accadrà con il file BruttaRisposta.CSS all’istruzione:<br />
<pre><link rel="stylesheet" href="BruttaRisposta.CSS" type="text/css" /></pre><br />
Mentre osservate con gioia la chiarezza e pulizia del codice che siamo riusciti a ottenere, una vocina potrebbe suggerirvi nella testa: «Ehi! Ma è la stessa cosa che succedeva nel C++ con l’istruzione #include &lt;iostream&gt;!»<br />
<br />
<br/>Esatto!<br />
<br />
A dire il vero da un punto di vista tecnico non sono la stessa cosa, ma il concetto di base è lo stesso.<br />
<br />
<br/>Ottimo! Ora abbiamo imparato a dividere il nostro codice su più file, che è una delle cose che rende il C++ così utile e apprezzato; sarà bene che sappiate, infatti, che noi ci sforzeremo di disubbidire perché siamo appena all’inizio, ma gli ambienti di programmazione in C++ fanno di tutto per convincere i programmatori a spezzare il codice su più file.<br />
<br />
Dividere il codice in più file è indispensabile in una forma di programmazione, che si chiama programmazione a oggetti, che ha molti estimatori.<br />
<br />
<br/>Adesso diamo un’occhiata al nostro file JavaScript, così bello pulito, e paragoniamo queste due righe:<br />
<pre>if ( 1 == controllaNome(utente) ) {<br />
risultato = 1;<br />
</pre><br />
che dovrebbero essere rispettivamente la 4 e la 19 – o giù di lì, se nell’incollare abbiamo lasciato qualche riga bianca.<br />
<br />
<br/>Notiamo subito che nella prima compare di nuovo il simbolo ‘==’, e immagino che per voi ormai sia chiaro cosa significa. Ma possiamo cercare ispirazione anche in ciò che abbiamo visto in Scratch:<br />
<br />
<br/>[[File:C++ Qt 02 Scratch 03 duerighe.png|C++ con Qt, parte II, due righe di Scratch]]<br />
<br />
La prima istruzione dice: prendi la risposta che ottieni e '''copiala''' in una cella di memoria a cui ho messo l’etichetta ''Nome'' (o, per brevità: ''nella variabile Nome'').<br />
<br />
La seconda invece dice: CONFRONTA se quello che è contenuto nella variabile ''amico1'' è uguale a quello che è contenuto nella variabile ''risposta''.<br />
<br />
<br/>Ecco dunque che Scratch ci offre due possibili modi di lavorare con le variabili: '''copiare''' i valori da una all’altra oppure '''confrontare''' il valore di una con il valore dell’altra.<br />
<br />
<br/>Anche il JavaScript ci consente di compiere queste due operazioni, con l’unico difetto che la sintassi da usare è così simile, nei due casi, che può capitare di confondersi.<br />
<br />
<br/>Mettiamo che io abbia creato una variabile qualsiasi, chiamiamola “mia_variabile”. In JavaScript:<br />
<pre>var mia_variabile;</pre><br />
A questo punto ci posso inserire dentro dei valori:<br />
<pre>mia_variabile = 4;</pre><br />
Dopo questa istruzione, dentro la cella di memoria etichettata mia_variabile si troverà il dato ‘4’.<br />
<br />
Dopo qualche migliaio di righe di programma, non siamo sicuri se questo dato sia stato modificato o no, per cui chiediamo di verificare, ossia diciamo al computer: «SE il dato contenuto in ''mia_variabile'' è uguale a 4, allora…»<br />
<br />
Ecco qui come viene:<br />
<pre>if ( mia_variabile == 4) …</pre><br />
Eccolo lì! Il mistero è svelato: il simbolo ‘==’ significa confronta; non serve a inserire dati dentro la variabile, bensì a leggerli e a porli in paragone con altri dati. Quindi i due simboli (‘=’ e ‘==’) somigliano, ma sono completamente diversi.<br />
<br />
Se per errore scriviamo:<br />
<pre>if ( mia_variabile = 4) …</pre><br />
ci facciamo del male da soli. Infatti quello che succederà dentro la parentesi sarà che il computer, ubbidendo alle nostre istruzioni, inserirà il dato ‘4’ nella variabile mia_variabile. Non solo, ma quando avrà finito, si confermerà da solo: «Tutto ok, operazione andata a buon fine», che è un segnale di ritorno positivo, ossia uguale a “vero”, e quindi potrebbe arrivare a questa brillante conclusione: il contenuto della parentesi è vero!<br />
<br />
Di conseguenza potrebbe eseguire '''sempre''' il codice SE… ALLORA, e '''mai''' quello ALTRIMENTI.<br />
<br />
<br/>Questo errore è veramente comune, tanto che c’è chi consiglia di abituarsi a scrivere alla rovescia:<br />
<pre>if ( 4 == mia_variabile ) …</pre><br />
che apparentemente può sembrare assurdo, ma invece funziona!<br />
<br />
Pensiamoci un po’. Il significato dell’istruzione è: «confronta il valore 4 con il dato contenuto nella variabile ''mia_variabile''.»<br />
<br />
Il che è assolutamente identico a dire: «confronta il dato contenuto contenuto in ''mia_variabile'' con il numero 4»!<br />
<br />
Il vantaggio è che, se per errore scrivessimo:<br />
<pre>if ( 4 = mia_variabile ) …</pre><br />
in linguaggi come il C++ il compilatore si fermerebbe e ci chiederebbe cosa cappero stiamo scrivendo. 4 è un numero, e non si può dire: scrivi il contenuto di mia_variabile in 4, non ha senso!<br />
<br />
Nel caso del JavaScript, invece, probabilmente l’esecuzione del codice si interromperebbe, facendoci capire che da qualche parte abbiamo sbagliato qualcosa.<br />
<br />
<br/>Possiamo ora leggere il nostro codice JavaScript per essere sicuri di averlo capito bene:<br />
<br />
Cominciamo dalla funzione ''cambioTesto'':<br />
<br />
<br/><u>'''var utente = document.getElementById("risposta").value;'''</u><br />
<br />
Dovrebbe essere chiara. Vuol dire:<br />
<br />
*trova l’elemento HTML con id="risposta"<br />
*leggi il suo contenuto<br />
*crea la variabile ''utente'' e inserisci questo contenuto lì dentro<br />
<br />
<u>'''if ( 1 == controllaNome(utente) ) {'''</u><br />
<br />
Questa può richiedere un po’ più di ragionamento.<br />
<br />
L’istruzione dice: CONFRONTA (‘==’) se ‘1’ e il valore di ritorno di ''controllaNome'' sono uguali…<br />
<br />
A questo punto, l’esecuzione salta da qui fin dentro la funzione ''controllaNome'' per cercare di avere il suo segnale di ritorno. Nel salto, si porta con sé il valore contenuto nella neonata variabile ‘utente’, perché dovrà inserirlo nella variabile che è lì in attesa, cioè quella che è scritta dentro la parentesi dopo il nome di funzione ''controllaNome''.<br />
<br />
<br/>Saltiamo anche noi dentro ''controllaNome'', ma ricordiamoci che poi dovremo tornare qui.<br />
<br />
<br/><u>'''function controllaNome(persona) {'''</u><br />
<br />
A queste punto, nella variabile ‘persona’ è stato copiato il contenuto della variabile ‘utente’.<br />
<br />
<br/><u>'''var risultato;'''</u><br />
<br />
Crea un’altra variabile.<br />
<br />
<br/><u>'''if (persona == "Mario" || persona == "Maria" || persona == "Gianni" || persona == "Gianna") {'''</u><br />
<br />
Ahia!<br />
<br />
Questa può far male, lo ammetto&nbsp;:)<br />
<br />
Leggiamola con calma. Il simbolo ‘||’ sembra una cosa molto misteriosa, ma vuol dire solo ‘oppure’.<br />
<br />
Lasciate che provi a tradurre questa istruzione in linguaggio corrente:<br />
<br />
«SE la variabile persona contiene ''Mario'' OPPURE la variabile persona contiene ''Maria'' OPPURE la variabile persona contiene ''Gianni'' OPPURE la variabile persona contiene ''Gianna'', ALLORA…»<br />
<br />
<br/>Non è così difficile da interpretare: il simbolo || dice al computer: me ne basta una.<br />
<br />
Ossia: io ti do due possibilità, una è quella a sinistra del simbolo e una è quella a destra; se anche solo una delle due è vera, allora mi devi rispondere ‘vero!’.<br />
<br />
Da un altro punto di vista: la condizione è falsa se '''TUTTE''' le condizioni sono false.<br />
<br />
<br/><u>'''risultato = 1;'''</u><br />
<br />
Si arriva a questo punto qui solo se la variabile ‘persona’ contiene uno dei 4 nomi sopra elencati.<br />
<br />
<br/><u>'''else{'''</u><br />
<br />
<u>'''risultato = 0;'''</u><br />
<br />
(ALTRIMENTI) Si arriva qui se l’utente non ha digitato nessuno dei 4 nomi previsti.<br />
<br />
<br/><u>'''return risultato;'''</u><br />
<br />
Se l’utente ha digitato uno dei 4 nomi, il segnale di ritorno sarà 1, altrimenti sarà 0.<br />
<br />
<br/><u>'''if ( 1 == controllaNome(utente) ) {'''</u><br />
<br />
Questo rigo l’avevamo già visto, ma ho preferito ritornare qui perché il processo fosse più chiaro.<br />
<br />
Adesso il computer ha il valore di ritorno di ''controllaNome'', che può essere solo 0 oppure 1 (abbiamo visto perché). Quindi può stabilire se il confronto con 1 dà vero o falso.<br />
<br />
Le ultime due righe non sto nemmeno a spiegarle perché spero siano chiarissime.<br />
<br />
<br />
<br />
=== Confessioni e paroloni ===<br />
<br />
Va bene, lo ammetto: lo sto facendo apposta.<br />
<br />
In effetti il codice JavaScript avrebbe potuto essere scritto così:<br />
<pre>function cambioTesto() {<br />
var utente = document.getElementById("risposta").value;<br />
<br />
if (utente == "Mario" || utente == "Maria" <br />
|| utente == "Gianni" || utente == "Gianna") {<br />
document.getElementById("testoDaCambiare").innerHTML = "Ciao, " + utente + "!";<br />
}<br />
else {<br />
document.getElementById("testoDaCambiare").innerHTML = "Non ti conosco, " + utente + "!";<br />
}<br />
}<br />
</pre><br />
e avrebbe funzionato lo stesso.<br />
<br />
<br/>Il fatto è che dobbiamo abituarci a scrivere funzioni, per cui anche in questo caso in cui si sarebbe potuta saltare, non è stata una cattiva idea scriverla: adesso abbiamo una funzione che svolge un compito preciso ed è possibile che un domani ci torni comodo un’altra volta. Nel qual caso, sappiamo dove trovarla. È un pezzo di codice riutilizzabile.<br />
<br />
<br/>E poi avete ragione: tutte queste righe di codice solo per spiegare che ‘==’ vuol dire ‘confronta’…<br />
<br />
Va bene, vorrà dire che scriveremo anche il codice con gli array, ossia l’equivalente delle liste di Scratch.<br />
<br />
<br/>Ma prima del divertimento dobbiamo levarci un sassolino dalla scarpa. Finora ho usato espressioni del tipo: “il dato contenuto nella cella di memoria etichettata…”; oppure: “creare una variabile”; o anche: “la funzione che abbiamo chiamato ''nomeFunzione''”; ecc. ecc.<br />
<br />
Adesso è venuto il momento di essere un gocciolino più precisi, nel senso di imparare un po’ di termini appropriati.<br />
<br />
<br/>Per ora preoccupiamoci solo delle variabili.<br />
<br />
È chiaro a tutti che una variabile è una cella di memoria a cui abbiamo dato un’etichetta e che quella cella di memoria il computer non la gestisce come vuole lui, bensì ci inserisce solo i dati che decidiamo noi? Okay, allora non userò più l’espressione ‘cella di memoria’, ma parlerò solo di variabili.<br />
<br />
Allora, il dato contenuto in una variabile è detto '''''valore''''' della variabile. Questo non è vero solo per le variabili numeriche, bensì anche per le variabili che contengono testo. Ossia, se in C++ scrivo:<br />
<pre>string amico1 = "Mario"</pre><br />
per riferirmi al dato contenuto nella variabile ‘amico1’ uno dovrò dire: «il valore della variabile ‘amico1’ di tipo string è “Mario”».<br />
<br />
A proposito, visto che abbiamo evitato l’argomento nella prima parte, sarà bene sapere fin d’ora che la parola inglese string '''NON''' significa stringa, come viene normalmente tradotta. Infatti le stringhe delle scarpe si chiamo ''laces''. String significa ''corda'', ''filo'', ''cordone'', ma in senso figurato anche ''serie'', ''sequenza'', e in quest’ultimo significato è stata adottata dalla matematica prima, e dall’informatica poi. Le variabili che dovevano contenere testo furono chiamate ''string'' a significare una ''sequenza di caratteri''.<br />
<br />
Adesso, se volessimo fare una lezione barbosissima, dovremmo affrontare un argomento davvero complicato, perché in C++ non potete creare una variabile, però potete dichiararla, definirla o inizializzarla, che sono tre cose diverse fra di loro. Però per ora tralasceremo questo argomento e troveremo un compromesso fra di noi, a livello amichevole: useremo le parole dichiarare e definire come se fossero sinonimi, tenendo però presente che verrà il momento di distinguere questi due passaggi.<br />
<br />
<br/>Ancora un punto e potremo tornare al nostro codice.<br />
<br />
Vi ricordate come siete stati bravi a scoprire che length() era una funzione perché il nome era seguito da parentesi tonde? Vi andrebbe bene se d’ora innanzi procedessimo sullo stesso sentiero, ossia se scrivessi i nomi di funzione sempre seguiti da parentesi tonde? Perché questa sarebbe la convenzione.<br />
<br />
Ad es., poco sopra avrei dovuto scrivere: “il valore di ritorno di controllaNome(), che può essere…”. Sarebbe molto comodo perché non correremmo più il rischio di confondere una variabile con una funzione.<br />
<br />
<br/>Chiusa la piccola parentesi sui termini, devo confessare un altro piccolo dispetto, nel caso qualcuno non se ne fosse accorto.<br />
<br />
Vi avevo detto che molto spesso si usa 0 come valore di ritorno dandogli senso positivo, ossia di “zero errori”. Questa però non è assolutamente una regola, anzi! Può darsi benissimo che una funzione restituisca 0 proprio per indicare una situazione di errore o comunque problematica. In tal caso, diciamo che andrebbe interpretata come “risultati 0”.<br />
<br />
Questo significa che:<br />
<br />
*quando usate una funzione preparata da qualcun altro (vedi ''length()''), dovete andare a leggere quali segnali di ritorno ha previsto chi l’ha scritta;<br />
*quando scrivete una funzione, vi potete considerare liberi di scegliere i valori di ritorno che preferite!<br />
<br />
Ad esempio, nella funzione ''controllaNome''… OPS! Volevo dire ''controllaNome()'', scusate!… Nella funzione ''controllaNome()'' abbiamo deciso di restituire 1 per significare “ho trovato una corrispondenza” e 0 per dire “nessuna corrispondenza trovata”.<br />
<br />
<br/>Visto che questo è un tutorial sul C++, vediamo infine come verrebbe il nostro codice in C++. Visto che stiamo parlando delle basi del C++, quelle che sono cambiate poco rispetto al C, la somiglianza con il JavaScript è davvero tanta:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int controllaNome(string persona);<br />
void cambioTesto();<br />
<br />
int main()<br />
{<br />
cambioTesto();<br />
return 0;<br />
}<br />
<br />
void cambioTesto()<br />
{<br />
string utente;<br />
cout << "Qual è il tuo nome? ";<br />
cin >> utente;<br />
<br />
if ( 1 == controllaNome(utente) ) {<br />
cout << "Ciao, " << utente << "!" << endl << endl;<br />
}<br />
else {<br />
cout << "Non ti conosco, " << utente << "!" << endl << endl;<br />
}<br />
}<br />
<br />
int controllaNome(string persona)<br />
{<br />
int risultato;<br />
<br />
if ( persona == "Mario" || persona == "Maria"<br />
|| persona == "Gianni" || persona == "Gianna" ) {<br />
risultato = 1;<br />
}<br />
else {<br />
risultato = 0;<br />
}<br />
<br />
return risultato;<br />
}<br />
</pre><br />
Direi che, se si è capito come funziona la versione JavaScript, non dovrebbe essere un problema decifrare questo codice.<br />
<br />
Anche in questo caso si può fare l’equivalente della versione breve:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
void cambioTesto();<br />
<br />
int main()<br />
{<br />
cambioTesto();<br />
return 0;<br />
}<br />
<br />
void cambioTesto()<br />
{<br />
string utente;<br />
cout << "Qual è il tuo nome? ";<br />
cin >> utente;<br />
<br />
if ( utente == "Mario" || utente == "Maria"<br />
|| utente == "Gianni" || utente == "Gianna" ) {<br />
cout << "Ciao, " << utente << "!" << endl << endl;<br />
}<br />
else {<br />
cout << "Non ti conosco, " << utente << "!" << endl << endl;<br />
}<br />
}<br />
</pre><br />
Per poter scrivere il nostro programmino con gli array, però, dobbiamo introdurre prima un’altra novità.<br />
<br />
Infatti Scratch ci offriva un’operazione interessante da compiere sulle liste, ossia questa qui:<br />
<br />
<br/>[[File:C++ Qt 02 Scratch 03 contiene.png|C++ con Qt, parte II, Scratch 03 contains]]<br />
<br />
<br/>Bisogna ammettere che è molto comoda: se ho una lista di 100 amici, con una sola istruzione posso sapere se un nome è in quella lista o no.<br />
<br />
Purtroppo il JavaScript non ci fornisce niente di equivalente, come non ce la fornirebbe il C. Il C++ invece, vedremo, sa essere un pochino più amichevole in questo genere di operazioni, per per arrivare a quello dobbiamo perdere un po’ di tempo sulla programmazione ‘tradizionale’.<br />
<br />
<br/>Vediamo di scoprire come si può risolvere il problema.<br />
<br />
La soluzione parte dal presupposto che la lista debba per forza essere ordinata. È vero che nella vita abbiamo spesso a che fare con liste apparentemente disordinate, come ad esempio la lista della spesa, in cui scriviamo le cose via via che ci vengono in mente, ma per il computer le cose non stanno così.<br />
<br />
Noi possiamo anche essere coscienti che quando abbiamo inserito i nomi dei nostri amici l’abbiamo fatto più o meno a caso, ma il computer non legge nei nostri pensieri: per quel che ne sa lui, quella sequenza può essere ordinata secondo un principio misterioso che nessuno gli ha spiegato. Questo significa che senza il nostro permesso non si azzarderà mai a cambiare l’ordine in cui abbiamo immesso i dati.<br />
<br />
Pertanto, se abbiamo inserito il nome “Gianni” per terzo, per quel che riguarda il computer quel nome rimarrà sempre in terza posizione, o almeno finché noi non gli diremo in modo esplicito di spostarlo.<br />
<br />
<br/>Attenzione! Questo non è vero per la rubrica del cellulare perché lì il programma è stato pensato apposta per tenere i nomi in ordine alfabetico. Anche questo si può fare, ovviamente, ossia si può creare una funzione che fa in modo che, via via che si inseriscono i nomi, vengano subito spostati nella posizione corretta secondo l’alfabeto.<br />
<br />
Quel che è importante tenere presente, però, è che bisogna specificare al computer di compiere questa azione, altrimenti lui non la farà: terrà gli oggetti nella sequenza in cui li abbiamo inseriti anche se noi non abbiamo usato nessun criterio.<br />
<br />
<br/>Perché specifico tutto questo? Perché, se ci riflettete un secondo, questo implica una cosa importante: il computer usa un ordine interno per tenere in memoria i dati che gli passiamo in una lista.<br />
<br />
In altre parole, quando scriviamo i nomi dei nostri amici, lui non memorizza in maniera confusa: «Che ha detto? Mario? Mario, okay. E poi? Maria? Mario o Maria? Si sarà mica sbagliato? E Gianna? E poi Gianni? Ma si chiamano tutti nella stessa maniera?»<br />
<br />
No, il nostro computer memorizzerà correttamente:<br />
<br />
Mario → posizione numero 1<br />
<br />
Maria → posizione numero 2<br />
<br />
Gianni → posizione numero 3<br />
<br />
Gianna → posizione numero 4<br />
<br />
<br/>Secondo voi questo significa che c’è un numero associato a ogni nome?<br />
<br />
Beh, per ora diciamo di sì, anche se più avanti incontreremo delle buffe creature come gli array associativi oppure le ''list'' del C++ in cui questo numero, se esiste, per noi è irraggiungibile e non ci si può riferire ad esso per recuperare i nostri dati. Ma per ora useremo delle liste un po’ meno eccentriche che hanno sempre questo numero associato a ogni dato.<br />
<br />
Intanto diciamo come si chiama questo numero: si chiama '''''indice'''''. Non bisogna pensare all’indice dei libri, bensì alla parola indice che usano i matematici. E sì, perché di creature bizzarre non è pieno solo il C++, ma anche fra gli esseri umani ce ne sono un sacco un po’ strampalati: pensate che ce ne sono alcuni a cui la matematica piace davvero e passano la vita a studiarla!<br />
<br />
Beh, c’è stato un momento nel passato in cui qualcuno di loro, osservando i numeri interi (vi ricordate cosa sono, vero?) si è chiesto: ma cosa hanno in comune fra di loro, tutti questi numeri? Beh, fra le varie risposte possibili ha osservato che ognuno di essi è separato dal successivo sempre della stessa quantità, che è 1. Ha anche realizzato che questo non è vero per tutti i numeri, ma lo è per gli interi.<br />
<br />
A quel punto ha deciso che era venuto il momento di creare un nuovo concetto matematico: la progressione aritmetica.<br />
<br />
La progressione aritmetica dice che si può scegliere una serie di numeri lunga quanto si vuole; se, osservandoli, ci si rende conto che sono tutti alla stessa ‘distanza’ fra di loro, allora sono in progressione. Ad esempio, se scegliamo -2, 0, 2, 4, 6, 8, questi sono sei numeri in progressione; la ‘distanza’ fra un numero e il successivo è sempre 2.<br />
<br />
Metto ‘distanza’ fra virgolette perché in matematica si dovrebbe dire ''ragione'' (ma, voglio dire, vi sembra ''ragionevole''?).<br />
<br />
Beh, se dei numeri sono in progressione, allora possiamo riferirci a loro dicendo: il '''primo''' della progressione, il '''secondo''' della progressione, il '''terzo''' della progressione, e così via. Sapete come si chiama questo numerino “primo”, “secondo”, “terzo”…? Eccolo lì: si chiama indice.<br />
<br />
<br/>Ora, quelli di voi che la pensano come me si confermeranno nell’idea che i matematici sono proprio strani, ma la realtà è che gli informatici sono molto più strani di loro! Infatti i matematici si erano messi d’accordo su un punto che mi sembrerebbe molto sensato: un indice deve comunque essere superiore a zero. Ossia, quando si chiamano i numeri della progressione non si può dire “lo zeeresimo della progressione”, ma bisogna cominciare con “primo”!<br />
<br />
Quando sono arrivati gli informatici (ossia quelli che traducono ''string'' con stringa, tanto per intenderci) hanno deciso che questo limite era inutile. «&nbsp;Ma no!» si sono detti. «Le nostre liste inizieranno con 0!» ''Et voilà'', a noi ci tocca prenderle così.<br />
<br />
<br/>La conclusione è che prima non ho scritto una cosa corretta. Il computer memorizzerà i dati che gli passiamo in questa maniera:<br />
<br />
Mario → posizione numero 0<br />
<br />
Maria → posizione numero 1<br />
<br />
Gianni → posizione numero 2<br />
<br />
Gianna → posizione numero 3<br />
<br />
<br/>A questo punto sappiamo che:<br />
<br />
*in ogni lista c’è un numero associato a ogni dato che inseriamo;<br />
*quel numero si chiama indice;<br />
*l’indice parte da 0, e non da 1 come molti potrebbero aspettarsi.<br />
<br />
Bene, ma come ci aiuta tutto ciò a scoprire se un nome si trova nella lista o no?<br />
<br />
In realtà è piuttosto semplice: basta scorrere la lista e paragonare ogni nome con quello che stiamo cercando.<br />
<br />
Ora dovete sapere che esiste un’istruzione che dice al computer: compi questa operazione, sempre la stessa, un certo numero di volte. Quindi noi possiamo scorrere la lista tramite questa istruzione in questo modo:<br />
<br />
#definisci una variabile che sia 0, chiamiamola ''indice'' per ricordarci a cosa serve;<br />
#definisci una variabile che sia 0; chiamiamola ''risultato'';#CONFRONTA il contenuto della lista alla posizione ''indice'' con la risposta dell’utente;<br />
#SE il contenuto è uguale, allora cambia ''risultato'' in 1;<br />
#aumenta il valore di ''indice'' di 1, in modo da passare alla posizione successiva;<br />
#riparti dal punto 1.<br />
<br />
Secondo voi siamo in grado di scrivere un programma del genere?<br />
<br />
Proviamo in JavaScript:<br />
<br />
<br/>'''1) definisci una variabile che sia 0, chiamiamola ''indice'''''<br />
<pre>var indice = 0;</pre><br />
<br/>'''2) definisci una variabile che sia 0; chiamiamola risultato;'''<br />
<pre>var risultato = 0;</pre><br />
<br/>'''3) CONFRONTA il contenuto della lista alla posizione indice con la risposta dell’utente;'''<br />
<br />
Qui bisogna conoscere la sintassi. Mettiamo che la lista si chiami “amici”; per riferirci all’indice della lista bisogna usare le parentesi quadre, in questo modo:<br />
<pre>amici[]</pre><br />
Quindi la prima posizione di Amici (ricordiamoci che la prima posizione è 0!) sarà:<br />
<pre>amici[0]</pre><br />
La seconda posizione sarà:<br />
<pre>amici[1]</pre><br />
eccetera.<br />
<br />
Quindi, per dire «la posizione indicata dal valore della variabile indice», bisognerà scrivere:<br />
<pre>amici[indice]</pre><br />
Come vedete è piuttosto semplice. A questo punto possiamo occuparci dell’istruzione CONFRONTA. Se partiamo dall’ultimo programmino che abbiamo scritto, la risposta dell’utente era contenuta nella variabile ''persona'', per cui:<br />
<pre>amici[indice] == persona</pre><br />
<br/>'''4) SE il contenuto è uguale, allora cambia risultato in 1;'''<br />
<pre>if ( amici[indice] == persona ) {<br />
risultato = 1;<br />
</pre><br />
<br/>'''5) aumenta il valore di indice di 1, in modo da passare alla posizione successiva;'''<br />
<br />
Questo si scrive in maniera un po’ ridicola, ma va preso così com’è:<br />
<pre>indice = indice + 1;</pre><br />
<br/>'''riparti dal punto 1.'''<br />
<br />
Bene, questo ancora non lo sappiamo scrivere perché non abbiamo ancora parlato dell’istruzione che ci consente di ripetere lo stesso blocco di codice un certo numero di volte. Quest’istruzione si chiama ''for loop'' ed è arrivato il momento di andarla a conoscere.<br />
<br />
<br/>A questo punto ci possiamo sbizzarrire con la versione con gli array. Ricordiamoci però di pronunciarli /əˈreɪ/ (ossia all’incirca come se in italiano fossero scritti eréi). Ecco il nostro codice:<br />
<pre>function cambioTesto(){<br />
var utente = document.getElementById("risposta").value;<br />
<br />
if ( 1 == controllaNome(utente) ) {<br />
document.getElementById("testoDaCambiare").innerHTML = "Ciao, " + utente + "!";<br />
}<br />
else {<br />
document.getElementById("testoDaCambiare").innerHTML = "Non ti conosco, " + utente + "!";<br />
}<br />
<br />
}<br />
<br />
function controllaNome(persona) {<br />
<br />
var risultato = 0;<br />
var amici = ["Mario", "Maria", "Gianni", "Gianna"];<br />
<br />
for(var indice = 0; indice < amici.length; indice = indice + 1 ) {<br />
if ( persona == amici[indice] ) {<br />
risultato = 1;<br />
}<br />
}<br />
<br />
return risultato;<br />
}<br />
</pre><br />
L’unica parte che potrebbe risultare misteriosa è come si scrive l’istruzione for. In effetti merita qualche chiarimento.<br />
<br />
L’istruzione ''for'' si chiama così perché è introdotta dalla parola ''for'' seguita da parentesi tonde. ''for'' serve per ripetere un blocco di codice un certo numero di volte, pertanto la cosa più importante è trovare il modo di informare il computer su '''esattamente quante volte''' deve ripetere il codice. Ciò che sta dentro le parentesi tonde serve proprio a questo.<br />
<br />
Di solito servono tre cose (a dire il vero non sono sempre tutte e tre obbligatorie):<br />
<br />
#una condizione iniziale – nel nostro caso, si parte da 0;<br />
#una condizione finale – nel nostro caso poniamo la condizione che il valore della variabile ''indice'' non abbia superato la dimensione (''length'') della lista, ossia ''indice'' deve essere minore (‘<’) della lunghezza della lista;<br />
#un’istruzione per decidere qual è il passo successivo – nel nostro caso, il valore di ''indice'' deve crescere continuamente di 1 per passare alla posizione successiva della lista.<br />
<br />
Il codice che deve essere ripetuto deve essere contenuto tra parentesi graffe.<br />
<br />
<br/>''for'' può non essere subito chiara, perciò cercheremo di trovare altri esempi in cui usarla.<br />
<br />
Adesso però diamo un’occhiata a come si creano gli array nel JavaScript. Come vedete la sintassi è ispirata a quella della dichiarazione di variabile:<br />
<pre>var amici = ["Mario", "Maria", "Gianni", "Gianna"];</pre><br />
Mi sembra piuttosto semplice: si scrivono i valori che si vogliono inserire usando una virgola per separarli. Il gruppo dei valori deve stare fra parentesi quadre.<br />
<br />
<br/>Adesso finalmente prendiamo il volo verso il C++.<br />
<br />
<br />
<br />
== Il bello di stare fra amici ==<br />
<br />
Il codice C++ si presenta subito con un’altra grana da risolvere, quindi tanto vale levarsi subito il dente:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int controllaNome(string persona);<br />
void cambioTesto();<br />
<br />
int main()<br />
{<br />
cambioTesto();<br />
return 0;<br />
}<br />
<br />
void cambioTesto()<br />
{<br />
string utente;<br />
cout << "Qual è il tuo nome? ";<br />
cin >> utente;<br />
<br />
if ( 1 == controllaNome(utente) ) {<br />
cout << "Ciao, " << utente << "!" << endl << endl;<br />
}<br />
else {<br />
cout << "Non ti conosco, " << utente << "!" << endl << endl;<br />
}<br />
}<br />
<br />
int controllaNome(string persona)<br />
{<br />
int risultato = 0;<br />
<br />
string amici[] = { "Mario", "Maria", "Gianni", "Gianna" };<br />
<br />
// Scopro quanto è grande il mio array<br />
int amici_length = sizeof(amici) / sizeof(amici[0]);<br />
<br />
for (int indice = 0; indice < amici_length; indice = indice + 1 )<br />
if ( persona == amici[indice] ) {<br />
risultato = 1;<br />
}<br />
<br />
return risultato;<br />
}<br />
</pre><br />
Cominciamo dagli aspetti più… innocui.<br />
<br />
<br/><u>'''string amici[] = { "Mario", "Maria", "Gianni", "Gianna" };'''</u><br />
<br />
Come possiamo vedere. il C++ insiste con la sua ‘pignoleria’: giacché un array è qualcosa di molto diverso da una variabile, non ammette che lo si possa definire usando la stessa sintassi che si usa per le variabili; al contrario, pretende che si specifichi con chiarezza che noi vogliamo '''davvero''' un array usando, dopo il nome, il simbolo ‘[]’.<br />
<br />
D’ora innanzi, quando useremo l’array dovremo sempre accompagnare il nome dal simbolo ‘[]’ anche se non abbiamo un indice da usare.<br />
<br />
C’è da dire, d’altro canto, che il C++ ha una sua coerenza interna perché i blocchi di codice sono sempre identificati dalle parentesi graffe e anche in questo caso non si rinvengono eccezioni.<br />
<br />
<br/><u>'''int amici_length = sizeof(amici) / sizeof(amici[0]);'''</u><br />
<br />
Questa è la parte che mi aspetto risulti più oscura.<br />
<br />
Intanto cerchiamo di capire a ''cosa'' serve, poi cercheremo di penetrare il meccanismo di ''come fa'' a fare ciò che ci serve.<br />
<br />
Torniamo a Scratch. Abbiamo visto che Scratch ci offriva una comoda funzione (“contiene”) che ci informava se un valore era contenuto in una lista o no. Poi abbiamo scoperto che nel JavaScript e nel C++ non era disponibile e ci siamo dovuti inventare un altro sistema per ottenere lo stesso risultato.<br />
<br />
Adesso soffermiamoci sul JavaScript. Questo, a sua volta, pur non offrendo l’istruzione “contiene”, ci veniva incontro con un’altra parolina magica, ''length'', la quale ci informava almeno su quanto era grande l’array, ossia su quanti dati vi erano contenuti.<br />
<br />
Arrivati al C++ ci imbattiamo in una sorpresa: nel C++ '''non''' c’è la parolina magica ''length''.<br />
<br />
<br/>«Ma come?» direte voi. «L’abbiamo usata poco tempo fa per ''string''!»<br />
<br />
Esatto, ma come vi dicevo il C++ è pignolo: chi ha scritto il codice per ''string'' ha previsto anche una funzione ''length()'' per ''string'', e chi ha scritto il codice per gli array non ha previsto una funzione equivalente. E il C++ non consente di prendere la funzione scritta per string e attaccarla a array.<br />
<br />
Spiacente. Non c’è e basta.<br />
<br />
<br/>Un attimo, però, sennò tra un po’ non ci capiamo più. Vi ricordate come si usava length() per string? Si usava così:<br />
<pre>string.length()</pre><br />
ossia, attaccandole tramite un punto.<br />
<br />
Quel punto sta a significare qualcosa di particolare, ossia vuol dire che ''length()'' non è una funzione che si può usare ovunque, bensì è una funzione che si può applicare '''soltanto''' a ''string''. È stata scritta, si può dire, su misura. Infatti abbiamo detto che è sì una funzione, ma di solito questo tipo di funzioni vengono chiamate '''''metodi''''', così non facciamo confusione. In particolare, si dice che ''length()'' è un metodo di ''string'', e in questa maniera si chiarisce che si può ‘attaccare’ solo a una variabile di tipo ''string''.<br />
<br />
<br/>Andando avanti troveremo un sacco di paroline magiche con i loro metodi e qualche volta li attaccheremo con un punto e altre volte con la buffa combinazione ‘->’ (es., string->length()), ma ora ne sappiamo ancora troppo poco per avventurarci in questo terreno.<br />
<br />
<br/>Lasciatemi finire il discorso sul pezzo di codice che abbiamo fra le mani e dopo andremo a sviscerare un po’ di misteri su queste paroline magiche e sui loro metodi e ci faremo domande del tipo: «Ma perché, se sono sempre metodi, ossia un particolare tipo di funzioni, nel C++ si deve scrivere ''length()'' e in JavaScript si scrive ''length''? Non bisogna mettere la parentesi tonda dopo il nome di funzione anche in JavaScript?»<br />
<br />
<br/>Abbiamo detto che in C++ non c’è un metodo per sapere quanti dati sono contenuti in un array. In questo caso noi sappiamo che sono 4, ma se è per questo sappiamo già che cosa c’è contenuto dentro. Di solito chi scrive un programma non ha tutte queste informazioni disponibili. Ad esempio, la lista dei nomi potrebbe arrivare da un database o da un’altra funzione e noi non sapremmo né quanti sono né quali sono.<br />
<br />
Il nostro obiettivo è quello di scrivere un codice che funzioni ''sempre'', non solo quando abbiamo tutta la pappa scodellata.<br />
<br />
Perciò ora ci dobbiamo inventare un sistema per scoprire quanto è grande questo array (ossia quanti dati contiene).<br />
<br />
<br/>Facciamo un esempio un po’ assurdo. Mettiamo che un giorno, per scommessa, dobbiate scoprire quanti piani ci sono dentro un’antica torre medioevale. Vi recate a darle un’occhiata e vi scoraggiate subito: la torre è altissima e senza finestre e avete scommesso che riuscirete a scoprirlo senza entrarci dentro. E non vi potete mica arrampicare lungo il muro!<br />
<br />
Come potete fare a scoprirlo?<br />
<br />
Per fortuna in quel momento incrociate la vostra amica Leonilda, la quale vi saluta: «&nbsp;Ciao! Cosa ci fai qui?»<br />
<br />
A quel punto le spiegate che dovete scoprire quanti piani ha la torre, ma non sapete come fare.<br />
<br />
Al che lei ci pensa un po’ su e poi vi sorride: «So io come puoi fare. Devi sapere che la torre è stata edificata da un gruppo di nani che ha costruito tutti piani dal soffitto bassissimo: io, per esempio, ci riesco a entrare precisa precisa, e sono alta un metro e sessanta. L’altezza della torre è scritta in questo cartello informativo, vedi? Sono 54,4 metri. Con queste informazioni, è facilissimo sapere quanti piani ci sono nella torre!»<br />
<br />
E in effetti subito intuite che la soluzione è<br />
<br />
Numero di piani = Torre&nbsp;: Leonilda<br />
<br />
e in pochi secondi riuscite a calcolare:<br />
<br />
Numero di piani = 54,4 m&nbsp;: 1,60 m = 5540 cm&nbsp;: 160 cm = 34 piani<br />
<br />
<br/>Beh, non è stato difficile, ma ora applichiamo lo stesso ragionamento qui.<br />
<br />
Il C++ ci offre uno strumento comodo: ''sizeof''.<br />
<br />
''sizeof'' è un’istruzione che ci informa di quanta memoria occupa un oggetto creato in un programma, per esempio una variabile o un array, il che è un altro modo di dire “quanto è grande”. Per la nostra torre abbiamo usato i metri, ma per parlare della memoria del computer dovremo usare un’unità di misura che non si vede: i byte.<br />
<br />
Stare a definire cos’è un byte non credo ci servirebbe a molto ora, mentre invece ci è utile sapere che ''sizeof'' ci informa su quanti byte vengono occupati da cose come gli array.<br />
<br />
<br/>A questo punto, se scriviamo ''sizeof(amici)'', possiamo scoprire quanti byte totali di memoria sono occupati dall’array ''amici''. Questo è un po’ come sapere l’altezza della torre.<br />
<br />
<br/>Se invece scriviamo ''sizeof(amici[0])'' scopriamo quanti byte sono occupati da un singolo dato inserito nell’array; nel caso particolare, il primo, quello in posizione 0 – ma noi abbiamo imparato che si dice “con indice 0”. Ma che sia il primo o l’ultimo o uno a caso non ha rilevanza: in un array tutti i dati occupano lo stesso spazio di memoria; visto che la maggior parte delle volte non siamo sicuri di quanti dati abbiamo nell’array, conviene riferirsi a quello in posizione 0, partendo dal presupposto che, se uno ha dichiarato un array, almeno un dato ce l’avrà messo!<br />
<br />
Comunque sia, quale che misuriamo, otterremo l’equivalente dell’altezza di un piano della torre.<br />
<br />
<br/>Quindi non ci resta che compiere la stessa operazione di prima, dividere l’altezza della torre per l’altezza di un piano e troveremo il numero dei piani.<br />
<br />
Parlando di array, dividendo la lunghezza complessiva in byte di un array per la lunghezza di un singolo dato otteniamo il numero dei dati contenuti.<br />
<br />
<br/>E questo è il significato di questa riga. ''By the way'', il simbolo ‘/’ in questo caso significa DIVIDI.<br />
<br />
<br/>Il risultato della divisione viene immagazzinato nella variabile ''amici_length'' (l’ho chiamata così perché fosse chiaro a cosa doveva servire).<br />
<br />
<br/>Beh, questo era lo soglio più grosso che dovevamo affrontare; superato questo, direi che il codice C++ è praticamente uguale a quello JavaScript.<br />
<br />
<br />
<br />
=== Una lista un po’ più simpatica ===<br />
<br />
A questo punto, se dovessi fare un tutorial molto serioso sul C++, dovrei soffermarmi un sacco su una novità come gli array e mostrare sia l’utilità che hanno, sia i limiti che delle volte presentano. Per non parlare poi dell’istruzione for, di cui bisogna portare almeno un altro paio di esempi se vogliamo essere sicuri di averla domata.<br />
<br />
<br/>Ma il mio intento non è certo quello di dire tutto. Ci sono fior fiore di manuali, scritti da gente molto, ma molto più competente di me sul C++, e sopra tutto ci sono i mentor al vostro fianco, che sono lì per aiutarvi nei dettagli che non riusciamo a affrontare. Il mio scopo è più quello di essere chiaro che non di essere esaustivo.<br />
<br />
Quindi voglio affrontare subito un dubbio amletico che sicuramente sta serpeggiando fra di voi, che è: «ma chi ce lo fa fare? Scratch è così chiaro e ha pure la funzione “contiene”. JavaScript come minimo non fa tanto il difficile su ''lentgh''… Ma perché perdere tempo su questa cosa cervellotica del C++?»<br />
<br />
Ebbene, sono qui a sollevare il vostro spirito: gioite perché ora andiamo a recuperare ''length'' per la coda.<br />
<br />
<br/>Il motivo per cui nel JavaScript si può attaccare ''length'' a un array è che nel JavaScript un array è un '''''oggetto'''''. Lo so che la parola è così comune da far sospettare che la stia usando in modo improprio, ossia come dire un affare, una cosa, una di quegli aggeggi che…<br />
<br />
Invece non è così: ''oggetto'' in informatica ha un significato molto preciso, ma finché non ne creeremo uno con le nostre mani qualunque cosa dica risulterà incomprensibile. Comunque per ora fidatevi: con il termine oggetto si intende un particolare blocco di codice che ha la sua brava etichetta, un po’ come le variabili o come ''string''. Un ''oggetto'' può avere dei metodi (ricordate? Funzioni che si attaccano con un punto o con ‘->’)<br />
<br />
Nel JavaScript un array è un oggetto; nel C++ '''non''' è un ''oggetto''.<br />
<br />
Quindi nel JavaScript possiamo usare ''length'' con un array, mentre nel C++ non possiamo farlo.<br />
<br />
<br/>Che sfortuna, vero? È una cosa triste, lo so. Bisognerebbe che anche nel C++ ci fosse un oggetto che si potesse usare come un array… Ehi, un momento! Ma c’è! Ma certo, è un ''vector''!<br />
<br />
Un ''vector'' fa le stesse cose di un array, ma, signore e signori, è un oggetto.<br />
<br />
<br/>Non ci resta che dare un’occhiata al nuovo codice C++ e rimandare le considerazioni a dopo.<br />
<pre>#include <iostream><br />
#include <vector><br />
<br />
using namespace std;<br />
<br />
int controllaNome(string persona);<br />
void cambioTesto();<br />
<br />
int main()<br />
{<br />
cambioTesto();<br />
return 0;<br />
}<br />
<br />
void cambioTesto()<br />
{<br />
string utente;<br />
cout << "Qual è il tuo nome? ";<br />
cin >> utente;<br />
<br />
if ( 1 == controllaNome(utente) ) {<br />
cout << "Ciao, " << utente << "!" << endl << endl;<br />
}<br />
else {<br />
cout << "Non ti conosco, " << utente << "!" << endl << endl;<br />
}<br />
}<br />
<br />
int controllaNome(string persona)<br />
{<br />
int risultato = 0;<br />
<br />
vector<string> amici = { "Mario", "Maria", "Gianni", "Gianna" };<br />
<br />
for (int indice = 0; indice < amici.size(); indice = indice + 1 ) {<br />
if ( persona == amici.at(indice) ) {<br />
risultato = 1;<br />
}<br />
}<br />
<br />
return risultato;<br />
}<br />
</pre><br />
Il problema di questo codice è che, se provate a compilarlo e a farlo partire, è possibile che Qt si blocchi. Ad alcuni si bloccherà e ad altri no. Coloro cui è andata bene devono portare un po’ di pazienza perché è bene risolvere questo problema fin da subito, invece che cercare di aggirarlo.<br />
<br />
Quelli cui si è bloccato dovrebbero trovarsi davanti a una schermata come questa:<br />
<br />
<br/>[[File:Qt Saluto 02 errore.png|C++ con Qt, parte II, Saluto errore]]<br />
<br />
<br/>Un giorno impareremo a leggere queste schermate e scopriremo che dentro sono contenute un sacco di informazioni per migliorare il codice che stiamo scrivendo, ma non è un argomento per i primi passi nel C++.<br />
<br />
<br/>Il ‘padre’ del C++ è il danese Bjarne Stroustrup, il quale fin dai primi anni ottanta stava cercando di aggiungere al linguaggio C il supporto per la programmazione a oggetti. Può quindi sembrare molto vecchio, almeno nei termini dell’informatica, ma nel corso degli anni è stato soggetto a molti miglioramenti. Anche nell’ultimo decennio ha subito molte revisioni, tra cui importantissima e molto sofferta è stata quella del 2011. Pensate un po’ che la discussione se introdurre o no le novità che molti proponevano fu iniziata nel 2008, ma erano così tanti a sollevare eccezioni e dubbi che i lavori si conclusero solo 3 anni dopo, nel 2011 appunto.<br />
<br />
In seguito a quella revisione, il suo stesso ideatore arrivò a dire che la trasformazione era stata tale che aveva l'impressione di lavorare con un linguaggio del tutto nuovo.<br />
<br />
<br/>Perché vi racconto questo? Per farvi inquadrare cos’è che ci blocca in questo momento. La complicazione la pone questa riga:<br />
<pre>vector<string> amici = { "Mario", "Maria", "Gianni", "Gianna" };</pre><br />
Anche a voi quel vector&lt;string&gt; potrebbe parere un po’ strano, ma non è quello che dà fastidio a Qt. Anzi, a dire il vero non c’è niente che dia fastidio a Qt, il piccoso è il compilatore.<br />
<br />
Non so se vi ricordate cosa si è detto quando si è presentato Qt: durante la fase di installazione, porta con sé un compilatore. Questo dovrebbe confermarvi che Qt è un ottimo ambiente di programmazione, ma non è di per sé un compilatore; però può ‘governare’ al posto nostro il compilatore che vogliamo usare.<br />
<br />
Tanto per farvelo sapere, se avete installato la versione ‘standard’ di Qt, il compilatore che si è portato appresso è l’ottimo GCC, che nella versione per Windows si chiama MinGw.<br />
<br />
<br/>«Tutto molto bello» starete pensando. «Ma perché è di cattivo umore, questo compilatore? Perché non fa quel che deve fare e basta?»<br />
<br />
Aspettiamo a trattarlo male, perché lui sta cercando di non farci sbagliare. Il fatto è che prima della revisione del 2001 ''vector'' non ammetteva di caricare i dati da un blocco fra parentesi graffe come fa un array. Bisognava usare un’altra sintassi con molte più righe da digitare.<br />
<br />
«Okay, ma ora siamo nel 2014, perciò… qual è il problema? Compili e basta.»<br />
<br />
Beh, io potrei darvi anche ragione, ma non è così che funziona lo sviluppo del software. Ci sono programmi che esistono da anni e anni e rimangono in buona sostanza gli stessi, magari con qualche aggiornamento ogni tanto.<br />
<br />
Quello che l’azienda di software vuole è che, quando scrive un piccolo aggiornamento per una nuova funzione o per risolvere un piccolo difetto, '''tutto''' il programma possa essere compilato di nuovo correttamente. Non vuole scoprire che intanto, da qualche parte del mondo, qualcuno ha deciso che, “Oh, guarda, questa versione del C++ non ci piace più, adesso la cambiamo in modo che il codice vada scritto così e cosà”, e d’un tratto il nuovo compilatore si rifiuta di accettare centinaia e centinaia di righe di codice che fino al giorno prima andavano benissimo!<br />
<br />
Per questo i creatori di GCC hanno deciso di fare in modo che al compilatore possa essere detto: questo codice qui lo compili secondo le regole che erano in vigore prima del 2011, e quest’altro codice secondo quelle dal 2011 in poi.<br />
<br />
<br/>Noi scriveremo tutto codice compatibile con le regole dal 2011 in poi, quindi ora ci basta informare il compilatore e la situazione si sbloccherà.<br />
<br />
<br/>Orbene, informare il compilatore non è difficile, ma noi perché dovremmo stare a domandarci come si fa? Non si è detto che Qt lo può governare per noi? È ovvio che può!<br />
<br />
È ora di scoprire cosa possono fare per noi quei file ‘in più’ che ci siamo ritrovati fra i piedi oltre al nostro ''main.cpp''.<br />
<br />
A noi interessa il file ''Saluto.pro'', per cui coraggio: fateci doppio click sopra ed apritelo:<br />
<br />
<br/>[[File:Qt Saluto 03 trovapro freccia.png|C++ con Qt, parte II, Saluto freccia]]<br />
<br />
<br/>Come vedete il file si apre nella colonna di destra, andando per il momento a coprire il contenuto di ''main.cpp''. Questa è una funzione molto comoda di Qt: i file si aprono uno sopra all’altro, di modo che possiamo recuperare il sottostante in ogni momento. Ancora non abbiamo cominciato a lavorare con più file contemporaneamente, però, per cui per recuperare main.cpp dovremo – DOPO, NON ORA! – fare doppio click sul suo nome.<br />
<br />
<br/>Adesso, '''sotto''' la riga:<br />
<pre>CONFIG -= qt</pre><br />
dobbiamo scrivere la seguente:<br />
<pre>CONFIG += c++11</pre><br />
di modo che il file venga così:<br />
<br />
<br/>[[File:Qt Saluto 04 c++11.png|C++ con Qt, parte II, Saluto c++11]]<br />
<br />
<br/>Per far riapparire il contenuto di main.cpp, fate doppio click sul suo nome. Poi compilate ed eseguite: adesso dovrebbe andare tutto liscio.<br />
<br />
<br/>RICORDATEVI QUESTI PASSAGGI PERCHÉ DOVREMO COMPIERLI PER OGNI PROGETTO DI QT! (almeno per ora)<br />
<br />
<br/>Dicevamo che l’istruzione<br />
<pre>vector<string> amici…</pre><br />
potrebbe causare un po’ di perplessità a qualcuno, e sarebbe comprensibile. In realtà non c’è niente di complicato. Confrontiamola con l’istruzione equivalente che fa uso degli array:<br />
<pre>string amici[] …</pre><br />
A ben guardare le due scritte sono equivalenti, giacché contengono le stesse istruzioni, anche se scritte in ordine diverso:<br />
<br />
#il nome della nostra variabile è sempre ‘amici’;<br />
#si tratta sempre di una variabile di tipo ''string'';#l’unica differenza è in come si dichiara un array (‘[]’) e in come si dichiara un ''vector'' (‘vector<>’).<br />
<br />
I ''vector'' sono oggetti di un tipo particolare, detti ''template'', i quali hanno la caratteristica di potersi adattare a diversi tipi di dati. Quindi noi avremmo potuto avere un ''vector'' di ''string'' come un ''vector'' di ''int'' e non sarebbe cambiato di una virgola il modo di usarli, solo che la dichiarazione iniziale sarebbe stata ''vector&lt;int&gt; amici''. Nel caso fosse stato un array, invece, avremmo scritto ''int amici[]''.<br />
<br />
<br/>Se la differenza fra i due fosse questa, non ci sarebbero motivi per andare a cercare i nostri amici ''vector''. Il motivo per cui abbiamo voluto presentarli è che i ''vector'', come le ''string'', portano con loro un sacco di metodi già pronti e impacchettati che ci semplificano la vita, come ad esempio il metodo ''size()'' che ci ha risparmiato di scrivere un’intera riga di codice.<br />
<br />
Rifletteteci un po’: se avessimo usato fin da subito ''vector'', non ci sarebbe stato nemmen bisogno di cominciare a parlare di torri medievali e di altezze dei piani! Gli oggetti del C++ sono lì per semplificarci le cose e possiamo cominciare a usarli senza doverli conoscere in ogni minimo dettaglio.<br />
<br />
<br/>Pensate che Qt ci offre un oggetto ancora più amichevole: QVector. Un QVector è un oggetto della libreria Qt che potremmo considerare un ''vector'' palestrato, giacché porta con sé un altra carrellata di metodi molto utili; uno di questi è ''contains'', il quale, indovinate un po’, ci informa se il nostro QVector contiene, tra i suoi dati, quello che stiamo cercando.<br />
<br />
Il che significa che non ci sarebbe più bisogno di un ciclo ''for'' per trovarlo.<br />
<br />
Detto in altre parole, se avessimo utilizzato un QVector tramite questa istruzione:<br />
<pre>QVector<string> amici…</pre><br />
dopo avremmo potuto procedere così:<br />
<pre>if ( amici.contains("Mario") || amici.contains("Maria")…</pre><br />
senza preoccuparci né del ciclo for né del size di vector.<br />
<br />
Questo è il motivo per cui vogliamo cominciare a conoscere fin da subito gli oggetti del C++ e anche passare appena possibile a quelli di Qt.<br />
<br />
<br/>A proposito, l’avete notato vero il rigo:<br />
<pre>#include <vector></pre><br />
all’inizio del nostro codice? Senza quello, il codice non funziona, chissà perché…&nbsp;;-)<br />
<br />
<br />
<br />
== Oltre l’orizzonte ==<br />
<br />
Se questo fosse un tutorial serio e ben strutturato ora rimarrei qui a farvi fare un sacco di prove con gli array e i ''vector'' e proverei a dimostrarvi quanti errori di programmazione si possono prevenire usando i secondi. Un’altra cosa che mi piacerebbe sottolineare è quanto l’apparente rigidità della sintassi del C++ possa contribuire a evitare errori e di come la ‘amichevolezza’ del JavaScipt possa ogni tanto nascondere trappole insidiose, ma il problema di trattare un argomento del genere è che si corre il rischio di ferire la suscettibilità di chi ama programmare in JavaScript e questo non rientra affatto fra i miei progetti. Vorrei quindi cambiare prospettiva e proporre un’altra visione: che ogni linguaggio che si usa ha i suoi pro e i suoi contro.<br />
<br />
Vediamolo con un esempio, sempre partendo da Scratch.<br />
<br />
=== Il gioco dei fiammiferi con Scratch ===<br />
<br />
Per questo gioco avremmo bisogno di 2 sprite, che io ho chiamato Giocatore1 e Giocatore2.<br />
<br />
<br />
<br />
==== Il codice di Giocatore1 ====<br />
<br />
Le variabili:<br />
<br />
<br/>[[File:Scra Fiammi 01.png|C++ con Qt, parte II, Scratch Fiammiferi 01]]<br />
<br />
<br/>Tenete presente che la variabile ‘presa’ dev’essere creata con una visibilità limitata al singolo ''sprite'', come si può vedere qui sotto:<br />
<br />
<br/>[[File:Scra Fiammi 02.png|C++ con Qt, parte II, Scratch Fiammiferi 02]]<br />
<br />
<br/>La variabile ‘Fiammiferi rimasti’ potrà invece essere lasciata “per tutti gli sprites”.<br />
<br />
Questo il resto del codice:<br />
<br />
<br/>[[File:Scra Fiammi 03.png|C++ con Qt, parte II, Scratch Fiammiferi 03]]<br />
<br />
<br />
<br />
==== Il codice di Giocatore2 ====<br />
<br />
Le variabili sono esattamente le stesse di prima, punto per punto.<br />
<br />
Il codice è composto dai seguenti spezzoni:<br />
<br />
<br/>[[File:Scra Fiammi 04.png|C++ con Qt, parte II, Scratch Fiammiferi 04]]<br />
<br />
<br/>[[File:Scra Fiammi 05.png|C++ con Qt, parte II, Scratch Fiammiferi 05]]<br />
<br />
<br/>Il codice Scratch è, come al solito, autoesplicativo.<br />
<br />
Metto soltanto in luce che il gioco non comincia quando si preme la bandierina verde, bensì quando si preme il tasto ‘p’. In alternativa si può premere ‘s’ per avere le spiegazioni sul gioco.<br />
<br />
<br/>Un tutorial in C++ non si rivolge a bambini molto piccoli, ma alcuni potrebbero non aver fatto algebra, pertanto potrebbero non capire la seguente istruzione:<br />
<br />
<br/>[[File:Scra Fiammi 06 moltineg.png|C++ con Qt, parte II, Scratch numero negativo]]<br />
<br />
<br/>Basterà dir loro che serve a trasformare ‘presa’ in un numero negativo, ma chi vuole sperticarsi in una lezione sulla moltiplicazione fra numeri positivi e negativi faccia pure&nbsp;:)<br />
<br />
<br/>Un altro punto su cui sarebbe utile soffermarsi sarebbe questo, perché ci introdurrà al meccanismo signals/slot delle librerie Qt:<br />
<br />
<br/>[[File:Scra Fiammi 07 segnale.png|C++ con Qt, parte II, Scratch invia segnale]]<br />
<br />
<br />
<br />
=== Cosa dire del codice? ===<br />
<br />
Va bene, lo ammetto, sono stato cattivo. Non si può vincere mai, penso ve ne siate accorti&nbsp;:)<br />
<br />
Il motivo per cui ho scelto questo gioco non è stato però per sadismo, bensì perché ci consente di introdurre un argomento che ci sta inseguendo fin dal primo tutorial: lo ''scope resolution'', espressione che fa temere il peggio, ma gode per lo meno del raro privilegio di essere di solito tradotta in maniera intelligente con “spazio di visibilità”, immagino perché, quando gli informatici hanno cercato di forzare quello ''scope'' in un qualcosa di similare in italiano, non è venuto loro in mente niente di appropriato.<br />
<br />
<br/>Per capire l’argomento torniamo alle due variabili ‘presa’ che esistono nel codice e osserviamo il loro comportamento. Ci si può rendere conto rapidamente che i loro valori si ‘muovono’ in maniera indipendente fra di loro e che ci sono istruzioni, come questa<br />
<br />
<br/>[[File:Scra Fiammi 08.png|C++ con Qt, parte II, Scratch variabile locale]]<br />
<br />
che influiscono solo su una delle due, ma lasciano inalterata l’altra.<br />
<br />
<br/>Il motivo è abbastanza evidente: quando le abbiamo create abbiamo specificato che ciascuna si riferisse a un solo sprite, e non a tutti gli sprite, pertanto il codice di uno sprite non è in grado di influenzare quella dell’altro sprite.<br />
<br />
In informatica si usa il termine ''visibilità'' per descrivere questo fenomeno e si dice, appunto, che una variabile è ''visibile'' solo dal codice dello sprite cui si riferisce.<br />
<br />
<br/>Per fare un paragone, è possibile che sia nella rubrica del vostro smartphone sia in quella del vostro compagno di tavolo sia presente il nome Ildebrando, però, stante il gran numero di Ildebrado che popolano questa nazione, potrebbero benissimo essere due persone diverse.<br />
<br />
Quindi il nome di una variabile è unico solo nel suo ''spazio di visibilità''.<br />
<br />
<br/>«Ma perché mai tutto queste complicazioni?» a qualcuno verrà da chiedere. «Non potevamo semplicemente creare due variabili con due nomi distinti, tipo presa1 e presa2, e lasciare che fossero visibili a tutti gli sprite?»<br />
<br />
Beh, certo, lo potevamo fare. Anche in JavaScript o in C++ potremmo, con molta sofferenza, raggiungere questo poco auspicabile traguardo.<br />
<br />
Anzi! Se le prese dei due giocatori sono visibili da entrambi, il codice del Giocatore2 si semplifica non poco, ossia si tagliano via i 4 ''if''. Credo che lascerò questa parte come esercizio; per chi ci vuole provare, il primo passo è cercare di capire come mai non si riesce a vincere – da qui si può partire per costruire un algoritmo di gran lunga più efficiente di quello utilizzato.<br />
<br />
<br/>Adesso, però, per penetrare nel mistero dello ''spazio di visibilità'', vediamo una delle possibili trasposizioni del gioco dei fiammiferi in JavaScript.<br />
<br />
<br />
<br />
=== Il gioco dei fiammiferi in JavaScript ===<br />
<br />
Cominciamo con il file in HTML5:<br />
<pre><!DOCTYPE html><br />
<br />
<html><br />
<head><br />
<meta charset="utf-8"><br />
<link href="comuni.css" rel="stylesheet" type="text/css"><br />
<script src="gioco21.js" type="text/javascript"></script><br />
<br />
<title>Gioco dei 21 fiammiferi</title><br />
</head><br />
<br />
<body><br />
<h1>Non giocate con i fiammiferi!</h1><br />
<br />
<div class="bordato"><br />
<p>Ci sono 21 fiammiferi. A ogni turno possiamo prenderne da 1 a 4. Chi rimane con l’ultimo ha perso.</p><br />
<p>Hai la prima mossa.</p><br />
<input type="button" value="Inizia a giocare" onclick="inizioGioco();" /><br />
</div><br />
<br />
<div><br />
<div class="sx"><br />
<p id="messaggio_cane">&nbsp;</p><br />
<br />
<p><img alt="Immagine di un cane" src="dog.jpg"></p><br />
<div><br />
<label for="g1" id="g1label" class="invisibile">Quanti fiammiferi prendo?</label><br />
<input id="g1" type="text" class="invisibile" /><br />
</div><br />
</div><br />
<br />
<div class="sx"><br />
<p id="numfiammi" class="molto_grande">Fiammiferi rimasti: 21</p><br />
</div><br />
<br />
<div class="sx"><br />
<p id="messaggio_anatra" class="destra">&nbsp;</p><br />
<br />
<p><img alt="Immagine di una anatra" src="duck.jpeg"></p><br />
</div><br />
</div><br />
<br />
<hr class="fine_float"><br />
<div><br />
<input id="cambio" type="button" value="Tocca a te!"<br />
class="invisibile" onclick="mossaCane();" /><br />
</div><br />
<br />
</body><br />
</html><br />
</pre><br />
Poi i CSS:<br />
<pre>img {<br />
width &nbsp;: 200px;<br />
height &nbsp;: 220px;<br />
}<br />
<br />
input {<br />
display &nbsp;: block;<br />
}<br />
<br />
label {<br />
display &nbsp;: block;<br />
}<br />
<br />
div.sx {<br />
float &nbsp;: left;<br />
}<br />
<br />
hr.fine_float {<br />
clear &nbsp;: both;<br />
height &nbsp;: 0;<br />
margin &nbsp;: 0;<br />
border &nbsp;: none;<br />
}<br />
<br />
.molto_grande {<br />
font-size &nbsp;: larger;<br />
font-weight &nbsp;: bold;<br />
}<br />
<br />
.bordato {<br />
border-color &nbsp;: teal;<br />
border-style &nbsp;: ridge;<br />
border-width &nbsp;: 2;<br />
padding &nbsp;: 0.6em;<br />
width &nbsp;: 40em;<br />
}<br />
<br />
.invisibile {<br />
visibility &nbsp;: hidden;<br />
}<br />
<br />
.visibile {<br />
visibility &nbsp;: visible;<br />
}<br />
<br />
.destra {<br />
text-align &nbsp;: right;<br />
}<br />
</pre><br />
Infine il JavaScript (il file deve chiamarsi “gioco21.js”):<br />
<pre>var fiammiferi;<br />
var elementi_invisibili = [];<br />
<br />
function inizioGioco() {<br />
fiammiferi = 21;<br />
numero_fiammiferi = document.getElementById('numfiammi');<br />
numero_fiammiferi.innerHTML = "Fiammiferi rimasti: " + fiammiferi;<br />
document.getElementById("messaggio_cane").innerHTML = "&nbsp;";<br />
document.getElementById("messaggio_anatra").innerHTML = "&nbsp;";<br />
<br />
trovaEleInvi();<br />
cambiaVisibilita(1);<br />
}<br />
<br />
function mossaCane() {<br />
var presa = document.getElementById("g1").value;<br />
var messaggio = document.getElementById("messaggio_cane");<br />
<br />
messaggio.innerHTML = "&nbsp;";<br />
<br />
// Controllo di non essere gia' rimasto con l'ultimo fiammifero<br />
if ( 1 == fiammiferi ){<br />
messaggio.innerHTML = "Mi sa che ha vinto lui...";<br />
cambiaVisibilita(0);<br />
return 0; // esco dalla funzione!<br />
}<br />
<br />
// Controllo che l'utente non abbia immesso un numero<br />
// minore di 1 o maggiore di 5<br />
if( presa > 0 && presa < 5 ) {<br />
messaggio.innerHTML = "Ho preso " + presa + " fiammiferi";<br />
fiammiferi -= presa;<br />
numero_fiammiferi.innerHTML = "Fiammiferi rimasti: " + fiammiferi;<br />
mossaAnatra();<br />
} else {<br />
messaggio.innerHTML = "Mi sa sche non posso farlo...";<br />
}<br />
}<br />
<br />
function mossaAnatra() {<br />
var messaggio = document.getElementById("messaggio_anatra");<br />
var presa = 0;<br />
<br />
messaggio.innerHTML = "&nbsp;";<br />
<br />
if( 1 < fiammiferi){<br />
presa = fiammiferi - 1;<br />
}<br />
if( 6 < fiammiferi){<br />
presa = fiammiferi - 6;<br />
}<br />
if( 11 < fiammiferi){<br />
presa = fiammiferi - 11;<br />
}<br />
if( 16 < fiammiferi){<br />
presa = fiammiferi - 16;<br />
}<br />
<br />
fiammiferi -= presa;<br />
messaggio.innerHTML = "Io prendo " + presa + " fiammiferi";<br />
numero_fiammiferi.innerHTML = "Fiammiferi rimasti: " + fiammiferi;<br />
<br />
if ( 1 == fiammiferi ) {<br />
mossaCane();<br />
}<br />
}<br />
<br />
function cambiaVisibilita(visibilita) {<br />
for (var indice=0; indice < elementi_invisibili.length; indice++){<br />
if( 1 == visibilita ) {<br />
elementi_invisibili[indice].setAttribute("class", "visibile");<br />
} else if ( 0 == visibilita ) {<br />
elementi_invisibili[indice].setAttribute("class", "invisibile");<br />
} else {<br />
alert("C'è un errore nel programma!");<br />
}<br />
}<br />
}<br />
<br />
function trovaEleInvi() {<br />
elementi_invisibili[elementi_invisibili.length] = document.getElementById("g1label");<br />
elementi_invisibili[elementi_invisibili.length] = document.getElementById("g1");<br />
elementi_invisibili[elementi_invisibili.length] = document.getElementById("cambio");<br />
}<br />
</pre><br />
Le immagini da utilizzare, mettendole nella stessa cartella del progetto, sono dog.jpg e duck.jpeg, che si trovano sullo wiki nelle rispettive pagine:<br />
<br />
*[[Media:Dog.jpg|Media:Dog.jpg]]<br />
*[[Media:Duck.jpeg|Media:Duck.jpeg]]<br />
<br />
<br/>Un’altra cosa: scrivere tutte le volte il nome JavaScript per esteso mi fa un po’ fatica. Un sacco di gente lo chiama semplicemente JS, perché non lo facciamo anche noi?<br />
<br />
<br/>Tanto vale che lo ammetta fin da subito: il codice JS che vi presento è un tantino complicato. Ormai abbiamo rotto il ghiaccio con l’idea di scrivere codice, per cui è inutile che continuiamo a fare i timidi. Vedrete che riusciremo a domare anche questo programma e ci insegnerà un sacco di cose.<br />
<br />
<br/>Lo scopo di questo programma è parlare prima di tutto di ''scope resolution'' perché è un argomento un po’ astratto, ma ne verranno fuori tanti altri via via che scorreremo le righe. Intanto diamo un’occhiata generale al programma, che ha ben 5 funzioni:<br />
<br />
#inizioGioco()<br />
#mossaCane()<br />
#mossaAnatra()<br />
#cambiaVisibilita<br />
#trovaEleInvi()<br />
<br />
Beh? Di cosa vi meravigliate? Il codice va spezzato in funzioni oppure non riusciremo mai a riutilizzarlo.<br />
<br />
Tra queste funzioni ce ne sono alcune che ci risulteranno ben chiare, ad esempio ''mossaCane()'' e ''mossaAnatra()'', che gestiscono il cambiamento del numero di fiammiferi in base alle scelte dei due giocatori. Altre invece ci risulteranno alquanto misteriose. Direi che la strategia più semplice per affrontarle è seguire il programma passo passo.<br />
<br />
<br/>Quando l’utente inizia, per prima cosa è invitato a leggere le spiegazioni e poi a premere il pulsante “Inizia a giocare”. Questo pulsante fa comparire la casella di testo dove il giocatore1 può inserire la sua scelta.<br />
<br />
Come fa a farlo?<br />
<br />
Guardiamo il codice HTML. Ci sono ben tre elementi che ‘nascono’ con associata la classe CSS ‘invisibile’:<br />
<br />
*la scritta “Quanti fiammiferi prendo?”<br />
*la casella di testo in cui scrivere il numero<br />
*il pulsante “Tocca a te”<br />
<br />
La classe ‘invisibile’ consiste nell’istruzione<br />
<pre>visibility&nbsp;: hidden;</pre><br />
Hidden in inglese vuol dire nascosto, e infatti quello che fa questa istruzione è di nascondere gli elementi a video. Ossia, essi ‘esistono’ nel codice HTML, ma non sono rappresentati a video.<br />
<br />
Quando la partita inizia, bisogna che questi elementi saltino fuori, e questo si può ottenere sostituendo la classe ‘invisibile’ con quella ‘visibile’.<br />
<br />
<br/>La pressione sul pulsante “Inizia a giocare” compie proprio questo passaggio tramite la funzione ''inizioGioco()''. Questo passaggio è reso necessario dal fatto che, quando il gioco finisce, sopra le due immagini compaiono scritte che non devono più apparire; non solo, ma il numero dei fiammiferi sarà 1 invece che 21; oltre a ciò, per comunicare all’utente che il gioco è finito, i tre elementi elencati sopra saranno resi invisibili di nuovo. Pertanto ci serve una funzione che rimetta a posto le cose prima dell’inizio di una partita.<br />
<br />
Però diamo anche un’occhiata anche a ciò che è scritto prima di ''InizioGioco()'':<br />
<pre>var fiammiferi;<br />
var elementi_invisibili = [];<br />
</pre><br />
Queste due istruzioni si limitano a definire una variabile e un array; la prima conterrà il numero di fiammiferi; la seconda invece i tre elementi che dovranno ‘apparire’ o ‘sparire’, ossia quei tre elencai poco sopra. Queste due istruzioni non sembrano aver nessuna particolarità, se non una che forse non salta all’occhio subito: si trovano entrambe fuori da ogni funzione.<br />
<br />
Torneremo tra pochissimo su questa osservazione, che è molto importante.<br />
<br />
<br/>Diamo un’occhiata a quali sono le operazioni preliminare a ogni partita, cioè a perché chiamiamo la funzione ''inizioGioco()'':<br />
<br />
<br/>'''fiammiferi = 21;'''<br />
<br />
Come si è detto, alla fine di una partita il numero di fiammiferi sarà uno, quindi all’inizio della partita successiva va riportato a 21. ‘fiammiferi’ è la variabile dichiarata fuori da ogni funzione. Come vedete, possiamo usarla senza problemi anche se non l’abbiamo definita qui.<br />
<br />
<br/>'''numero_fiammiferi = document.getElementById('numfiammi');'''<br />
<br />
'''numero_fiammiferi.innerHTML = "Fiammiferi rimasti: " + fiammiferi;'''<br />
<br />
<br/>A questo punto aggiorniamo la scritta “Fiammiferi rimasti: 21” sullo schermo. Quindi, ‘numero_fiammiferi’ è una variabile che ci consente di accedere al del codice HTML. Lì dentro, tramite il metodo ''innerHTML'', andiamo a inserire la frase: “Fiammiferi rimasti: 21”. Facciamo caso a una cosa: ''numero_fiammiferi'' è stata definita senza la parolina ''var'' davanti.<br/>'''document.getElementById("messaggio_cane").innerHTML = "&nbsp;";''' '''document.getElementById("messaggio_anatra").innerHTML = "&nbsp;";''' Queste due righe dovrebbero essere chiare, eccetto che forse non tutti sanno cosa vuol dire ''&nbsp;'' nello HTML. A dir la verità nel Coder Dojo abbiamo già avuto modo di scoprire che ''è'' serve per inserire la lettera ‘è’ e ''ò'' per inserire la lettera ‘ò’, perciò dovrebbe essere piuttosto naturale dedurre che anche ''&nbsp;'' serva per inserire una lettera. Beh, quasi, ma non proprio: è solo un modo complicato di inserire uno spazio. Avremmo anche potuto scrivere document.getElementById("messaggio_cane").innerHTML = " "; document.getElementById("messaggio_anatra").innerHTML = " "; con uno spazio dentro le virgolette e avrebbe funzionato lo stesso (provare per credere). Il fatto è che non tutti usano un semplice editor di testo per scrivere codice HTML; esistono anche dei programmi appositi, molto più evoluti. Una delle caratteristiche di questi programmi è che rimettono a posto il codice via via che lo si scrive; ad esempio se scriviamo &lt;p&gt;, questi programmi aggiungono automaticamente un subito dopo; e come questa, fanno anche tante altre cose per semplificarci la vita. Una di queste cose, però, è eliminare gli elementi vuoti. Ossia, se a un certo punto scrivete<br />
<pre><p></p></pre><br />
oppure<br />
<pre><p> </p></pre><br />
con solo uno spazio dentro, il programma, quando lo vede, pensa: «Che cosa ci sta a fare qui un paragrafo senza niente dentro? Si è dimenticato di levarlo, quel pasticcione… Eh, meno male che ci sono io qui a rimettere a posto le cose, sennò chissà dove andremmo a finire!», e, detto fatto, lo cancella.<br />
<br />
Se invece scrivete<br />
<pre><p>&nbsp;</p></pre><br />
ottenete lo stesso risultato, ma il programma per scrivere codice HTML, se ne state usando uno, ve lo lascia stare.<br />
<br />
<br/>'''trovaEleInvi();'''<br />
<br />
Questa istruzione fa saltare il programma nella funzione ''trovaEleInvi()''. Seguiamolo.<br />
<br />
<br/>'''elementi_invisibili[elementi_invisibili.length] = document.getElementById("g1label");'''<br />
<br />
'''elementi_invisibili[elementi_invisibili.length] = document.getElementById("g1");'''<br />
<br />
'''elementi_invisibili[elementi_invisibili.length] = document.getElementById("cambio");'''<br />
<br />
Le tre istruzioni di per sé dovrebbero essere molto semplici.<br />
<br />
In pratica, carichiamo dentro l’array ''elementi_invisibili'' gli elementi che, come abbiamo scoperto, dovremmo ogni tanto far apparire e ogni tanto far sparire.<br />
<br />
Potrebbe essere un po’ difficile decifrare quel ''elementi_invisibili.length''. Avevamo scoperto che ''length'' serviva per scoprire quanti elementi c’erano in un array, adesso in apparenza sembra che serva per un’altra cosa.<br />
<br />
Beh, non proprio. Ragioniamoci un po’ su, partendo proprio dal nostro codice.<br />
<br />
All’inizio l’array ''elementi_invisibili'' è vuoto; questo significa che ''elementi_invisibili.length'' è 0. Bene. Ma non abbiamo detto che il primo elemento di un array è quello in posizione 0?<br />
<br />
Quindi, se noi vogliamo inserire il primo elemento nella prima posizione di una array, ossia in posizione 0, vuol dire che dobbiamo scrivere:<br />
<pre>elementi_invisibili[0] = …</pre><br />
Però anche ''elementi_invisibili.length'' è 0, pertanto le due istruzioni ''elementi_invisibili[0]'' e ''elementi_invisibili[elementi_invisibili.length]'' sono perfettamente identiche.<br />
<br />
<br/>Quindi la prima delle tre righe inserisce l’elemento HTML &lt;label id="g1label"&gt; nella posizione 0 di ''elementi_invisibili''.<br />
<br />
<br/>A questo punto, però, la dimensione del nostro array è cambiata perché dentro c’è un elemento. Quindi ''elementi_invisibili.length'' non restituirà più 0, bensì 1.<br />
<br />
Quindi la seconda riga<br />
<pre>elementi_invisibili[elementi_invisibili.length] = document.getElementById("g1");</pre><br />
inserirà l’elemento HTML &lt;input id="g1"&gt; nella seconda posizione dello array, ossia in posizione 1.<br />
<br />
Ciò significa che scrivere<br />
<pre>elementi_invisibili[elementi_invisibili.length] = qualcosa;</pre><br />
istruisce il computer a inserire ‘qualcosa’ nella prima posizione libera dell’array, ossia in coda agli altri dati contenuti.<br />
<br />
<br/>Attenzione! Di nuovo dobbiamo far attenzione al fatto che l’array ''elementi_invisibili'' è stato definito da un’altra parte, ossia all’inizio del nostro programma. Anche in questa occasione, ci limitiamo ad usarlo, proprio come se fosse stato definito in questa funzione.<br />
<br />
<br/>A questo punto la funzione ''trovaEleInvi()'' è finita è il computer torna in ''inizioGioco()''. E noi con lui.<br />
<br />
<br/>'''cambiaVisibilita(1);'''<br />
<br />
Questa istruzione ci fa saltare nella funzione ''cambiaVisibilita()''.<br />
<br />
Mettiamoci d’accordo su un altro parolone: in informatica chiamare una funzione si dice ‘'''invocare'''’ una funzione.<br />
<br />
<br/>'''cambiaVisibilita(visibilita)'''<br />
<br />
Questa funzione fa una cosa semplice, anche se a vederla sembra piena di righe complicate.<br />
<br />
Come vedete accanto al nome della funzione c’è il nome di una variabile; dentro quella variabile, come sappiamo, finirà il valore che viene trasmesso alla funzione quando l’abbiamo chiamata – ossia, invocata.<br />
<br />
Se quel valore è 1, la funzione mostra i tre elementi contenuti nell’array ''elementi_invisibili''.<br />
<br />
Se quel valore è 0, li nasconde.<br />
<br />
<br/>Fateci caso anche qui: stiamo usando l’array ''elementi_invisibili'' né più né meno come se l’avessimo definito in questa funzione.<br />
<br />
<br/>Tutto è gestito dal ciclo ''for'', che incrementa di uno il valore della variabile ‘indice’ da 0 fino a che non è '''inferiore''' al numero di dati contenuti nello array, ossia al massimo a 2 (perché 3 non sarebbe più inferiore alla dimensione dell’array, bensì uguale).<br />
<br />
Il valore di questa variabile è poi usato come indice dell’array (e proprio perché fosse chiara questa sua funzione l’abbiamo chiamata ‘indice’, ma avrebbe potuto benissimo chiamarsi ‘Genoveffa’ e non sarebbe cambiato nulla).<br />
<br />
Il metodo setAttribute si occupa di far cambiare agli Elementi HTML la classe CSS associata, ''visibile'' o ''invisibile''.<br />
<br />
<br/>In questo caso è stato passato il valore 1 ed ecco spiegato come fanno i 3 famigerati elementi ad apparire.<br />
<br />
<br/>A questo punto il primo ‘passaggio’ è finito. Siamo in attesa che l’utente scriva un numero nella casella di testo &lt;input id="g1"&gt; e prema il pulsante “Tocca a te”.<br />
<br />
La pressione di quel pulsante invoca la funzione ''mossaCane()'', alla tentazione di esaminare la quale non possiamo resistere:<br />
<br />
<br/>'''var presa = document.getElementById("g1").value;'''<br />
<br />
Qui dichiariamo una variabile all’interno di una funzione tramite la parola ''var''. Ne sentivate la mancanza, di un’istruzione così?&nbsp;:)<br />
<br />
Direi che non c’è molto da aggiungere: la variabile conterrà ciò che ha immesso l’utente della casella di testo &lt;input id="g1"&gt;<br />
<br />
<br/>'''var messaggio = document.getElementById("messaggio_cane");'''<br />
<br />
'''messaggio.innerHTML = "&nbsp;";'''<br />
<br />
Anche se l’avevamo già fatto prima, qui sostituiamo il testo che compare sopra l’immagine del canino con uno spazio, ossia con qualcosa di apparentemente vuoto.<br />
<br />
Il fatto è che il pulsante “Inizia a giocare” non sarà più premuto fino alla fine della partita, ma la presa dei fiammiferi si effettuerà più volte prima di allora, e ogni volta qui dovrà comparire un testo diverso.<br />
<br />
<br/>'''// Controllo di non essere gia' rimasto con l'ultimo fiammifero'''<br />
<br />
Questo è un commento per ricordarsi cosa si sta facendo. Il nostro codice dovrebbe esserne pieno, ma col fatto che poi commento tutto dopo, per ora non sto a scriverli. Però tenete presente che scrivere i commenti è una delle attività più importanti del programmare.<br />
<br />
<br />
<br />
{| class="wikitable"<br />
|-<br />
! <center>Codice</center><br />
! <center>Spiegazioni</center><br />
|-<br />
| if ( 1 == fiammiferi ){<br />
| Il blocco successivo si attiverà solo quando il giocatore1 sarà rimasto con l’ultimo fiammifero<br />
|-<br />
| messaggio.innerHTML = "Mi sa che ha vinto lui...";<br />
| Vi ricordate cosa conteneva ‘messaggio’? L’elemento HTML<br />
<br />
<br />
|-<br />
| cambiaVisibilita(0);<br />
| Si invoca la funzione ''cambiaVisibilita()'' passandogli il valore 0, ossia dicendole di far ‘sparire’ i 3 ormai arcinoti elementi<br />
|-<br />
| return 0;<br />
| Questa riga forza l’uscita dalla funzione ''mossaCane()'' senza che venga eseguito il resto del codice – Se il giocatore1 ha perso, non c’è più motivo di fargli prendere altri fiammiferi – Attenzione! Non è rilevante che non ci sia nessuno a ‘raccogliere’ il valore restituito da ''mossaCane()'', l’importante è che ''return'' blocchi il codice.<br />
|-<br />
| <nowiki>} </nowiki><br />
| fine del blocco di codice ''if''<br />
|}<br />
<br />
<br/>'''if( presa > 0 && presa < 5 ) {'''<br />
<br />
Anche questa istruzione può lasciare interdetti, ma è molto più semplice di quel che appaia.<br />
<br />
Abbiamo visto sopra il simbolo ‘||’ che vuol dire OPPURE.<br />
<br />
Ebbene questo simbolo simbolo qui, ‘&&’, vuol dire '''E'''.<br />
<br />
In altre parole, la frase si dovrebbe leggere: SE il valore di ‘presa’ è maggiore di 0 E il valore di ‘presa’ è inferiore a 5, ALLORA…<br />
<br />
Tutto ciò è un modo un po’ complicato di dire che ‘presa’ deve stare fra 1 e 4.<br />
<br />
Il simbolo ‘&&’ istruisce il computer a considerare falsa l’espressione dentro la parentesi se anche solo una delle condizioni è falsa.<br />
<br />
Detto alla rovescia, l’espressione dentro la parentesi è considerata vera SOLO SE '''TUTTE''' le condizioni sono vere.<br />
<br />
<br/>Quindi, se l’utente inserisce un numero tra 1 e 4, si entra nel blocco, altrimenti si prosegue con il blocco ''else''.<br />
<br />
<br/>'''messaggio.innerHTML = "Ho preso " + presa + " fiammiferi";'''<br />
<br />
Si aggiorna la scritta sopra l’immagine del canino.<br />
<br />
<br/>'''fiammiferi -= presa;'''<br />
<br />
Un’altra cosa che non abbiamo ancora visto, ma anche qui non c’è da farsi prendere dal panico.<br />
<br />
Mettiamo che io abbia una variabile, ‘gigetto’, e che sia uguale a 5.<br />
<pre>var gigetto = 5;</pre><br />
Se scrivo<br />
<pre>gigetto = gigetto + 1;</pre><br />
‘gigetto’ diventa uguale a 6. Solo che l’istruzione è considerata molto lunga da qui pigroni degli informatici, perciò si sono messi d’accordo a trovare un modo di non ripetere la parola ‘gigetto’ e alla fine hanno trovato questa diavoleria:<br />
<pre>gigetto += 1;</pre><br />
Carino, eh? Badate bene, non vuol dire nulla di particolare: se ‘gigetto’ era uguale a 6, adesso diventa uguale a 7.<br />
<br />
Però non è finita qui. Visto che la maggior parte delle volte il valore di una variabile cambia solo di 1, si sono inventati un metodo ancora più breve, cioè questo:<br />
<pre>gigetto++;</pre><br />
Anche se può sembrare illeggibile, il significato delle 3 istruzioni è esattamente il medesimo; quindi, partendo dal 7 di prima, adesso ‘gigetto’ è diventata 8.<br />
<br />
Tutto qui.<br />
<br />
<br/>E lo stesso vale per il segno meno:<br />
<pre>gigetto -= 3;</pre><br />
fa tornare ‘gigetto’, da 8 che era, di nuovo a 5; e<br />
<pre>gigetto--;</pre><br />
addirittura a 4.<br />
<br />
<br/>Invece le altre operazioni si devono ‘accontentare’ della sintassi con il segno di uguale, ossia *= e /=.<br />
<br />
Per rendere le cose semplici, riporto qui un po’ di esempi che dovrebbero essere più chiari di mille parole:<br />
<br />
<br />
<br />
{| class="wikitable"<br />
|-<br />
| var unvalore = 10;<br />
| unvalore == 10<br />
|-<br />
| unvalore++;<br />
| unvalore == 11<br />
|-<br />
| unvalore -= 9;<br />
| unvalore == 2<br />
|-<br />
| unvalore *= 7;<br />
| unvalore == 14<br />
|-<br />
| unvalore--;<br />
| unvalore == 13<br />
|-<br />
| unvalore += 5;<br />
| unvalore == 18<br />
|-<br />
| unvalore /= 3;<br />
| un valore == 6<br />
|}<br />
<br />
Pertanto l’istruzione<br />
<pre>fiammiferi -= presa;</pre><br />
è del tutto identica a<br />
<pre>fiammiferi = fiammiferi - presa;</pre><br />
e si limita a far calare il numero dei fiammiferi del valore di ‘presa’.<br />
<br />
<br/>ANCORA UNA VOLTA STIAMO USANDO UNA VARIABILE CHE NON È STATA DICHIARATA NELLA FUNZIONE IN CUI CI TROVIAMO COME SE LO FOSSE STATA.<br />
<br />
<br/>'''numero_fiammiferi.innerHTML = "Fiammiferi rimasti: " + fiammiferi;'''<br />
<br />
Dovrebbe essere chiaro.<br />
<br />
<br/>'''mossaAnatra();'''<br />
<br />
Andiamo a vedere cosa combina questa funzione.<br />
<br />
Però, attenzione!, dopo NON torneremo in ''mossaCane()'' perché il codice restante, ossia lo ALTRIMENTI del blocco ''if'' è talmente ovvio che siete del tutto in grado di decifrarlo da soli.<br />
<br />
<br/>'''var messaggio = document.getElementById("messaggio_anatra");'''<br />
<br />
'''messaggio.innerHTML = "&nbsp;";'''<br />
<br />
Queste due righe erano staccate fra di loro, ma se si guardano così di seguito direi che non hanno bisogno di chiarimenti.<br />
<br />
<br/>'''var presa = 0;'''<br />
<br />
Neanche questa ha bisogno di chiarimenti.<br />
<br />
<br/>'''if( 1 < fiammiferi){'''<br />
<br />
:'''presa = fiammiferi - 1;'''<br />
<br />
'''}'''<br />
<br />
'''if( 6 < fiammiferi){'''<br />
<br />
:'''presa = fiammiferi - 6;'''<br />
<br />
'''}'''<br />
<br />
'''if( 11 < fiammiferi){'''<br />
<br />
:'''presa = fiammiferi - 11;'''<br />
<br />
'''}'''<br />
<br />
'''if( 16 < fiammiferi){'''<br />
<br />
:'''presa = fiammiferi - 16;'''<br />
<br />
'''}'''<br />
<br />
Questo blocco può essere poco chiaro dal punto di vista della logica, ma direi che non presenta difficoltà sintattiche.<br />
<br />
Comprenderne la logica è lasciato come esercizio. Si può partire dall’invertire le condizioni; ossia, invece di scrivere ''if( 1 < fiammiferi)'' si può scrivere ''if( fiammiferi > 1 )'', il ché dovrebbe rendere il meccanismo più chiaro.<br />
<br />
<br/>'''fiammiferi -= presa;'''<br />
<br />
Ne abbiamo già vista una identica poco sopra.<br />
<br />
<br/>'''messaggio.innerHTML = "Io prendo " + presa + " fiammiferi";'''<br />
<br />
'''numero_fiammiferi.innerHTML = "Fiammiferi rimasti: " + fiammiferi;'''<br />
<br />
Non ci vedo difficoltà.<br />
<br />
<br/>'''if ( 1 == fiammiferi ) {'''<br />
<br />
:'''mossaCane();'''<br />
<br />
Questa posso capire che lasci perplessi.<br />
<br />
In pratica si dice: se rimane un solo fiammifero, non stare a chiedere all’utente quanti fiammiferi vuole prendere, ma salta subito nella funzione ''mossaCane()'' dove c’è un blocco ''if'' che gestisce questa situazione.<br />
<br />
<br/>Scommetto che morite dalla voglia di sapere perché ho continuato a ripetere quella frase “stiamo usando una variabile definita da un’altra parte come se l’avessimo definita qui!”. È giunto il momento che vi risponda.<br />
<br />
<br/>Prendiamo in esame la variabile ‘presa’. Anzi: prendiamo in esame le due variabili ‘presa’. Dico due variabili perché si tratta di due variabili completamente diverse fra di loro, i cui valori non si intersecano mai.<br />
<br />
Una delle due è dichiarata in ''mossaCane()'' e l’altra in ''mossaAnatra()''. Orbene, anche se hanno lo stesso nome, per il computer sono due variabili diverse e tutto ciò che faremo a una non avrà alcuna influenza su ciò che faremo all’altra. Se cambiamo, incrementiamo, azzeriamo o diminuiamo il valore di una, l’altra rimarrà inalterata.<br />
<br />
<br/>Questo è ciò che si intende con ''spazio di visibilità'' di una variabile ed è un concetto importantissimo.<br />
<br />
Una variabile che è dichiarata all’interno di una funzione può essere vista '''SOLO''' dal codice di quella funzione. Fuori da quella funzione è assolutamente invisibile. Se dichiarate una variabile con lo stesso nome, beh, si tratta semplicemente di un’altra variabile.<br />
<br />
Le funzioni che possono essere viste solo all’interno della loro funzione si dice che hanno ''visibilità locale'' oppure che sono ''variabili locali''.<br />
<br />
Nel C++ (ora vedremo anche il codice per quel linguaggio) le cose stanno all’incirca nella stessa maniera, solo che, essendo lui così (uffa! Mamma mia!) pedante, ci aggiunge un’altra complicazione, che è il ''mascheramento'' (che noi non useremo).<br />
<br />
<br/>Del tutto diverse sono invece la variabile e l’array che abbiamo dichiarato '''fuori da ogni funzione'''.<br />
<br />
Riguardate il codice e i commenti: usiamo quella variabile e quell’array un po’ ovunque, ma il loro contenuto non va mai perso.<br />
<br />
Ossia, anche se carichiamo i valori nell’array ''elementi_invisibili'' dentro la funzione ''trovaEleInvi()'', tutte le volte che invochiamo la funzione ''cambiaVisibilita()'' li ritroviamo lì ad aspettarci.<br />
<br />
E lo stesso vale per ''fiammiferi'': quando ne abbiamo bisogno la usiamo e dentro ci troviamo sempre proprio il numero che ci aspettiamo di trovarci, anche se la modifichiamo una volta in ''mossaCane()'' e una volta in ''mossaAnatra()''.<br />
<br />
Si dice che queste variabili, ossia quelle dichiarate fuori di ogni funzione, hanno ''visibilità globale''. Oppure semplicemente che sono ''variabili globali''.<br />
<br />
<br/>Anche in questo caso, consoliamoci, il C++ vede le cose dallo stesso punto di vista.<br />
<br />
Anche se, lo ammetto, se stessimo facendo un corso serissimo dovrei considerare il caso di una variabile ‘così tanto’ globale da dover essere vista addirittura da un altro file… No, no, è troppo complicato! Lasciamo stare, non posso stare qui a dirvi che basta scrivere ''extern'' all’inizio della dichiarazione di variabile…<br />
<br />
<br/>Orbene, adesso mi metto qui in attesa di qualcuno che, avendo spulciato il codice per bene, mi fa notare che ''numero_fiammiferi'' è dichiarata all’interno della funzione ''inizioGioco()'', e quindi dovrebbe avere visibilità locale, ma è usata anche in altre funzioni proprio come se avesse visibilità globale…<br />
<br />
C’è qualcuno che se n’è accorto? Bravi!<br />
<br />
<br/>Ecco, questo è un punto su cui il JavaScript e il C++ non andrebbero mai d’accordo.<br />
<br />
Nel JavaScript basta non mettere la parola ''var'' prima di una variabile e quella sarà automaticamente considerata una variabile globale ANCHE SE è dichiarata all’interno di una funzione.<br />
<br />
Sorpresa!<br />
<br />
Quindi ‘numero_fiammiferi’ è una variabile globale a tutti gli effetti, e questo solo perché non c’è scritto ''var'' davanti.<br />
<br />
<br/>Ora mettiamoci nell’ordine d’idee di un programmatore in C++.<br />
<br />
Si è detto che il C++ ci costringe a spezzare il nostro codice in blocchi. Più avanti vederemo che ci spinge anche a mettere questi blocchi su file diversi, proprio perché sia diviso in modo coerente e ordinato. Il motivo per cui è così minuzioso è perché è un linguaggio che è stato concepito per consentire a molte persone di lavorare sullo stesso progetto senza intralciarsi fra di loro. In altre parole, essendo il codice diviso in blocchi e i blocchi in file, in una squadra anche numerosa possiamo dirci: «Io lavoro su questo blocco e tu su quello» e andiamo avanti ognuno con ciò che deve fare senza curarci degli altri.<br />
<br />
Ora fate conto di stare lavorando in rete con altre duecento persone di tutti i paesi del mondo e di scoprire che il vostro codice non funziona più perché qualcuno degli altri duecento, in qualcuna delle innumerevoli funzioni che ha scritto, ha usato un nome di variabile che avete usato anche voi, ma si è dimenticato di scriverci davanti ''var''…<br />
<br />
Anzi, meglio: immaginate di essere voi ad aver dimenticato di scrivere ''var'', ma di non avere la più pallida idea di quale funzione possa essere e di aver già scritto decine e decine di file di codice… E i vostri colleghi sono tutti fermi in attesa che voi risolviate il problema perché sennò non si può compilare il programma!<br />
<br />
Simpatico, nevvero?&nbsp;:)<br />
<br />
<br/>Si capisce allora perché nei forum ci siano tante polemiche: per un programmatore in JavaScript la possibilità di creare variabili globali in qualsiasi momento è una gran comodità; per un programmatore in C++ è una trappola da evitare come la peste. Entrambi hanno le loro buone ragioni.<br />
<br />
Nel C++, sia ben chiaro, al di là del fatto che non esiste la parola ''var'', è previsto un solo modo di dichiarare una variabile globale: crearla fuori da ogni funzione.<br />
<br />
<br/>Non è questa l’unica discrepanza fra il modo di vedere le cose le programmatore C++ e quello del programmatore JavaScript. Vi ricordate che tempo fa ci siamo chieste perché nel JavaScript la parola ''length'' si scrivesse senza parentesi tonde? Allora non avevamo dato una risposta, lasciando che si potesse ipotizzare si trattava solo di una diversa sintassi. Beh, le cose sono un po’ più complicate di così.<br />
<br />
Ne JavaScript ''length'' non è un metodo (ossia una particolare funzione), bensì è una ''proprietà'', ossia un particolar tipo di variabile.<br />
<br />
<br/>Quando ci si riferisce a un oggetto, la parola ''proprietà'' indica una variabile; questa variabile però non può essere usata come ci pare, bensì come è stato previsto dal creatore dell’oggetto. Chi ha creato gli array ha previsto che ''length'' contenesse il numero di dati inseriti; non si può usarla a caso, ma solo per gestire questo dato.<br />
<br />
Fatto sta che il valore di ''length'', essendo una variabile, può essere modificato a piacere.<br />
<br />
Guardate un po’ cosa succede qui:<br />
<pre><!DOCTYPE html><br />
<br />
<html><br />
<head><br />
<meta charset="utf-8"><br />
<script type="text/javascript" src="provaLength.js"></script><br />
<title>Prova della proprietà length</title><br />
</head><br />
<br />
<body><br />
<input type="button" value="Premi per provare" onclick="provaLength()"><br />
<p id="output1">&nbsp;</p><br />
<p id="output2">&nbsp;</p><br />
<p id="output3">&nbsp;</p><br />
</body><br />
</html><br />
</pre><br />
Quello sopra è il codice HTML, questo il JavaScript (il file deve chiamarsi “provaLength.js”):<br />
<pre>function provaLength() {<br />
var output1 = document.getElementById("output1");<br />
var output2 = document.getElementById("output2");<br />
var output3 = document.getElementById("output3");<br />
<br />
var mioarray = [];<br />
var dimensione = mioarray.length;<br />
output1.innerHTML = "Dimensione array: " + dimensione;<br />
<br />
mioarray.length = 3;<br />
dimensione = mioarray.length;<br />
output2.innerHTML = "Dimensione array: " + dimensione;<br />
<br />
mioarray[0] = "Una frase a caso";<br />
dimensione = mioarray.length;<br />
output3.innerHTML = "Dimensione array: " + dimensione;<br />
}<br />
</pre><br />
Anche in questo caso la grande flessibilità e semplicità di utilizzo del JavaScript può dare risultati inattesi, se non si sa cosa si sta facendo.<br />
<br />
Anche nel C++ si potrebbero creare oggetti con delle ''proprietà'', ossia delle variabili ad essi connesse, che si possono modificare a piacere, ma, all’interno del pignolo C++, è considerato un '''pessimo''' modo di scrivere codice e nessuno degli oggetti che fanno parte dello standard presenta una proprietà del genere.<br />
<br />
State quindi molto attenti, nel JavaScript, quando elaborate qualcosa come<br />
<pre>if ( mioarray.length == miavariabile) {…</pre><br />
a scrivere correttamente il simbolo ‘==’ e non ‘=’, perché potreste modificare il valore di length.<br />
<br />
<br/>Ancora una nota: se vi ricordate avevamo detto che era necessario, all’inizio del file C++, riportare un elenco delle funzioni che si erano scritte. In quel caso avevamo detto che così il compilatore poteva garantirci che non ci fossero duplicati.<br />
<br />
Quello che abbiamo trattato qui è diverso, ma simile: anche in questo caso ci dobbiamo garantire che, all’interno dello stesso ''spazio di visibilità'' non ci siano nomi duplicati.<br />
<br />
<br/>Bene, coraggio, il C++ ci aspetta.<br />
<br />
<br />
<br />
=== Il gioco dei fiammiferi in C++ ===<br />
<br />
Non possiamo però creare un programma che riguarda il gioco dei fiammiferi in un progetto che si chiama “Saluto”!<br />
<br />
È ora di creare un nuovo progetto. Non sto qui a ripetervi i passi: tornate a consultare il primo tutorial.<br />
<br />
Come nome (“Name”) mettiamo “Gioco21” e come cartella (“create in”) la stessa, “…ProgrammiCpp/CppQt” o come si chiama il percorso che avete creato.<br />
<br />
<br/>[[File:Qt Gioco21 01.png|C++ con Qt, parte II, Qt Gioco21 01]]<br />
<br />
<br/>Vi dovreste ritrovare in una situazione simile a quella in cui ci siamo trovati nella prima versione del programma “Saluto”. Infatti Qt crea sempre un file main.cpp in cui inserisce il codice “Hello world!”.<br />
<br />
<br/>[[File:Qt Gioco21 02.png|C++ con Qt, parte II, Gioco21 02]]<br />
<br />
<br/>Avete la sicurezza di trovarvi in un nuovo progetto leggendo ciò che compare sulla barra del titolo (“Gioco21”).<br />
<br />
Anche in questo caso del codice “Hello world!” non ce ne facciamo di niente e lo sovrascriveremo.<br />
<br />
<br/>Ecco il nostro codice:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int fiammiferi;<br />
<br />
void spiegazioni();<br />
void mossaCane();<br />
void mossaAnatra();<br />
<br />
int main()<br />
{<br />
spiegazioni();<br />
fiammiferi = 21;<br />
<br />
// Questo tipo di blocco si chiama ciclo do-while.<br />
// Funziona così:<br />
// la riga "do {" identifica solo l'inizio del blocco.<br />
// Il programma la legge e viene informato solo che<br />
// prima o poi incontrerà la scritta "}while(...".<br />
// Il computer continua a eseguire le istruzioni fino alla<br />
// fine del blocco, poi legge dentro la perentesi tonda<br />
// dopo la parola while.<br />
// "while" funziona come "if", ossia propone una condizione<br />
// di cui il computer deve decidere se sia vera o falsa.<br />
// Se la condizione è vera, allora il computer torna alla<br />
// parola "do" e ricomincia il ciclo.<br />
do {<br />
mossaCane();<br />
mossaAnatra();<br />
} while ( 1 < fiammiferi );<br />
<br />
// Se siamo arrivati qui, vuol dire che il numero dei fiammiferi<br />
// è diventato uguale a 1.<br />
cout << endl << "* * * * * * * * * * * * * * * * * * * * * * * * * * *"<br />
<< endl;<br />
cout << "Mi spiace, sei rimasto con l'ultimo"<br />
" fiammifero..." << endl;<br />
cout << "Ho vinto io." << endl;<br />
cout << "* * * * * * * * * * * * * * * * * * * * * * * * * * *"<br />
<< endl << endl;<br />
<br />
return 0;<br />
}<br />
<br />
void spiegazioni()<br />
{<br />
cout << "Ci sono 21 fiammiferi." << endl;<br />
cout << "Ne possiamo prendere da 1 a 4 per volta." << endl;<br />
cout << "Chi rimane con l'ultimo ha perso." << endl;<br />
cout << endl << "Hai la prima mossa." << endl << endl;<br />
}<br />
<br />
void mossaCane()<br />
{<br />
int presa = 0;<br />
<br />
// In questo momento presa == 0,<br />
// pertanto la condizione successiva sarà ritenuta *vera*.<br />
// Infatti l'istruzione dice:<br />
// FINCHE' presa sarà minore di 1 OPPURE presa sarà<br />
// maggiore di 5...<br />
// presa è al momento minore di 1, pertanto si entra<br />
// nel ciclo while.<br />
// Il ciclo while si ripete finché è necessario, ossia anche<br />
// all'infinito, in attesa che la condizione diventi falsa.<br />
while ( presa < 1 || presa > 4 ){<br />
<br />
cout << "Quanti fiammiferi prendi (da 1 a 4)? " << endl;<br />
cin >> presa;<br />
<br />
if( presa < 1 || presa > 4) {<br />
cout << "Spiacente. Devi prendere almeno un fiammifero, "<br />
"ma non più di quattro..." << endl << endl;<br />
}<br />
<br />
}<br />
<br />
// Se siamo usciti dal blocco 'while' vuol dire che<br />
// abbiamo ottenuto un numero da 1 a 4<br />
fiammiferi -= presa;<br />
cout << "Hai preso " << presa << " fiammiferi." << endl;<br />
cout << "Ne rimangono " << fiammiferi << "." << endl;<br />
}<br />
<br />
void mossaAnatra()<br />
{<br />
int presa;<br />
<br />
if( 1 < fiammiferi ) {<br />
presa = fiammiferi - 1;<br />
}<br />
if( 6 < fiammiferi ) {<br />
presa = fiammiferi - 6;<br />
}<br />
if( 11 < fiammiferi ) {<br />
presa = fiammiferi - 11;<br />
}<br />
if( 16 < fiammiferi ) {<br />
presa = fiammiferi - 16;<br />
}<br />
<br />
fiammiferi -= presa;<br />
<br />
cout << "Io prendo " << presa << " fiammiferi." << endl;<br />
cout << "Adesso ne rimangono " << fiammiferi << "." << endl<br />
<< endl;<br />
}<br />
</pre><br />
Come vedete, per quanto mi sia sforzato di rimanere il più attaccato possibile alla versione JavaScript, via via che entriamo nel mondo dal C++ siamo costretti ad allontanarci dagli altri.<br />
<br />
Il C++ non nasce per interagire strettamente con un file HTML, ma volendo potrebbe anche farlo, solo che sarebbe così dispendioso in termini di quantità di codice da scrivere da non avere alcun senso (ammesso e non concesso che a me riuscisse scriverlo, quel codice!).<br />
<br />
Per poter presentare una finestra carina come quella che riusciamo a fare sommando le potenzialità di HTML5 e JavaScript, ossia con le immagini dei due giocatori e il testo disposto per bene in uno spazio organizzato, dobbiamo aspettare di usare le librerie Qt.<br />
<br />
<br/>Però possiamo intanto introdurre dei nuovi costrutti, ossia nuovi modi di ‘costruire’ blocchi, come i due cicli ''do-while'' e ''while'' che compaiono in questo programma. Riguardo a essi non saprei bene cosa aggiungere rispetto a ciò che ho scritto sotto forma di commento nel codice.<br />
<br />
<br/>Entrambi questi tipi di blocchi servono a ripetere un certo numero di istruzioni per un numero illimitato di volte, ossia finché una determinata condizione da vera diventa falsa. Sono quindi del tutto diversi da ''for'' perché quel blocco nasce per essere ripetuto un numero predeterminato di volte.<br />
<br />
Questo tipo di blocchi, ossia quelli che si devono ripetere più di una volta, vengono di solito chiamati cicli o, in inglese, ''loop''; in questo caso la traduzione non è, diciamo, andata male, ma il significato prevalente di ''loop'' è quello di “anello”, “circuito”, “asola”, “cappio”… In un fiume, ad esempio, “ansa”.<br />
<br />
Per indicare una ripetizione del blocco si usa il parolone ''iterazione''.<br />
<br />
<br/>Anche se è comodo avere due tipi di blocchi, un tipo che si ripete un numero non preordinato di volte e un altro di cui posso con facilità controllare quante volte si ripete (detto con il parolone: quante ''iterazioni'' compie), la verità è che posso sempre forzare la natura di questi due blocchi per far loro fare ciò che più mi piace.<br />
<pre>int iterazioni = 0;<br />
while ( iterazioni < 10 ) {<br />
iterazioni++;<br />
}<br />
</pre><br />
è un blocco che di per sé nasce per essere ripetuto un numero imprecisato di volte, ma possiamo prevedere con grande facilità che compirà esattamente 10 iterazioni.<br />
<pre>for ( int iterazioni = 0; iterazioni < 10; iterazioni++ ) {<br />
iterazioni--;<br />
}<br />
</pre><br />
nascerebbe per ripetersi solo 10 volte, ma temo che proseguirà per sempre…<br />
<br />
<br/>La differenza tra il ciclo ''do-while'' e il ciclo ''while ''è che in quest’ultimo la condizione viene letta subito, perciò, se questa è falsa, il ciclo non viene proprio eseguito; invece nel primo la condizione viene letta alla fine, perciò almeno una volta le istruzioni contenute vengono eseguite.<br />
<br />
<br/>L’unica variabile globale che rimane nel nostro codice C++ è ‘fiammiferi’, ma, essendo i programmatori C++ così riottosi nel dichiarare variabili globali, non possiamo evitare di esercitarci nella domanda se davvero sia indispensabile avere una variabile globale. E la risposta è ovviamente no, non è indispensabile.<br />
<br />
Infatti ‘fiammiferi’ potrebbe essere dichiarata all’interno di ''main()'' e passata alle varie funzioni durante l’invocazione – ad esempio, ''mossaCane(fiammiferi)''.<br />
<br />
Le medesime funzioni potrebbero restituire un intero, che sarebbe il nuovo numero di fiammiferi rimasti, ossia il valore da inserire nella variabile ‘fiammiferi’.<br />
<pre>int mossaCane(int nuovavariabile);<br />
int mossaAnatra(int nuovavariabile);<br />
</pre><br />
Il valore restituito andrebbe, in main(), inserito nella variabile ‘fiammiferi’, che a questo punto diverrebbe una pura variabile locale.<br />
<br />
<br/>Tutto questo è lasciato come esercizio perché non è al di sopra delle vostre capacità, anche se ci sono diverse modifiche da apportare al programma.<br />
<br />
<br/>Scrivere questo codice vi potrebbe far apparire molto desiderabile l’uso delle variabili globali, e non sarebbe una percezione del tutto sbagliata. Per fortuna il C++ ha inventato un altro modo per gestire questo problema, ossia le variabili che devono essere modificate da più funzioni.<br />
<br />
<br />
<br />
Allora reggetevi perché stanno per arrivare ''references'' e puntatori.<br />
[[Category:C++|Category:C++]]</div>
Robi
https://kata.coderdojo.it/wiki/index.php?title=C%2B%2B
C++
2014-11-03T12:11:39Z
<p>Robi: </p>
<hr />
<div>[[Category:Principale]]</div>
Robi
https://kata.coderdojo.it/wiki/index.php?title=Tutorial_C%2B%2B_con_Qt
Tutorial C++ con Qt
2014-11-03T12:08:24Z
<p>Robi: Aggiunto class wikitable alla terza tabella, eliminati gli altri stili</p>
<hr />
<div>= Tutorial C++ con le librerie Qt =<br />
<br />
== Finalità di questo tutorial ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
== Di cosa stiamo parlando ==<br />
<br />
=== Che cos’è il C++ ===<br />
<br />
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''.<br />
<br />
==== Linguaggi compilati e linguaggi interpretati ====<br />
<br />
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é.<br />
<br />
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.<br />
<br />
Questa trasformazione può avvenire in due maniere:<br />
<br />
#ci può essere un programma che legge rigo per rigo quello che abbiamo scritto e lo trasforma sul momento in linguaggio macchina;<br />
#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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
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++.<br />
<br />
Vediamo alcune differenze fra questi due modi di scrivere codice.<br />
<br />
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.<br />
<br />
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’.<br />
<br />
La contropartita è che un linguaggio interpretato può funzionare solo se sul computer è installato il relativo interprete.<br />
<br />
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.<br />
<br />
== Cosa ci serve ==<br />
<br />
Uff! Abbiamo già dovuto spiegare un sacco di cose, non è vero? Coraggio, è quasi finita!<br />
<br />
<br />
<br />
=== Pulsanti ed eventi: come farne a meno? ===<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<pre><!DOCTYPE html><br />
<br />
<html lang="it-IT"><br />
<br />
<head><br />
<meta charset="utf-8"><br />
<br />
<title>JavaScript e HTML5 - un pulsante che non fa quasi niente</title><br />
<br />
<script type="text/javascript"><br />
function cambioTesto(){<br />
document.getElementById("testoDaCambiare").innerHTML = "Ecco! Hai visto? Sono cambiato&nbsp;:-)";<br />
}<br />
</script><br />
<br />
</head><br />
<br />
<body><br />
<br />
<div><br />
<label for="cambiaTesto">Pulsante che modificherà il testo sottostante --></label><br />
<input type="button" id="cambiaTesto" value="Premimi per cambiare il testo"<br />
onclick="cambioTesto();" /><br />
</div><br />
<br />
<div><br />
<p>Il testo contenuto in questo paragrafo cambierà quando sarà premuto il pulsante soprastante.</p><br />
</div><br />
<br />
</body><br />
<br />
</html><br />
</pre><br />
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.<br />
<br />
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.<br />
<br />
<br />
<br />
{| class="wikitable"<br />
|-<br />
! <center>'''Codice'''</center><br />
! <center>'''Spiegazioni'''</center><br />
|-<br />
| &lt;!DOCTYPE html&gt;<br />
| dichiaro che userò la versione HTML nota come HTML5.<br />
|-<br />
| &lt;html lang="it-IT"&gt;<br />
| inizio del codice HTML e dichiarazione che userò la lingua italiana.<br />
|-<br />
| &lt;head&gt;<br />
| 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.<br />
|-<br />
| &lt;meta charset="utf-8"&gt;<br />
| 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: &lt;meta content="text/html; charset=utf-8" http-equiv="Content-Type"&gt;<br />
|-<br />
| &lt;title&gt;JavaScript e HTML5 - un pulsante che non fa quasi niente&lt;/title&gt;<br />
| la scritta che comparirà sulla finestra del browser.<br />
|-<br />
| &lt;!-- … --&gt;<br/><br />
| questi sono commenti che servono a rendere più chiaro il codice a chi lo legge e non hanno alcun riflesso sulla pagina web.<br />
|-<br />
| &lt;script type="text/javascript"&gt;<br />
| inizio del codice Javascipt. Questo lo guardiamo tutto insieme dopo.<br />
|-<br />
| &lt;/script&gt;<br />
| fine del codice Javascript (vedi rigo precedente).<br />
|-<br />
| &lt;/head&gt;<br />
| fine delle istruzioni per il browser (vedi qualche rigo sopra).<br />
|-<br />
| &lt;body&gt;<br />
| inizio della parte che viene mostrata a chi visita la pagina web.<br />
|-<br />
| &lt;div&gt;<br />
| serve a creare un blocco ordinato di righe e a distinguerle da quelle contenute in una altro blocco<div>…</div><br />
|-<br />
| &lt;label for="cambiaTesto"&gt;Pulsante che modificherà il testo sottostante -->&lt;/label&gt;<br />
| Questa fa comparire la scritta “Pulsante che modificherà; il testo sottostante”.<br />
|-<br />
| &lt;input type="button" id="cambiaTesto" value="Premimi per cambiare il testo" onclick="cambioTesto();" /&gt;<br/><br />
| 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.<br />
|-<br />
| &lt;/div&gt;<br />
| fine del blocco ordinato di istruzioni.<br />
|-<br />
| &lt;p&gt;Il testo contenuto in questo paragrafo cambier&agrave; quando sar&agrave; premuto il pulsante soprastante.&lt;/p&gt;<br />
| Questa fa comparire la scritta “Il testo contenuto in questo paragrafo cambierà quando sarà premuto il pulsante soprastante.”<br />
|-<br />
| &lt;/body&gt;<br />
| fine della parte che viene mostrata a chi visita la pagina web.<br />
|-<br />
| &lt;/html&gt;<br />
| fine del codice HTML.<br />
|}<br />
<br />
In pratica a noi interessano le seguenti righe:<br />
<br />
Quella che inizia con ''&lt;p&gt;'' e finisce con ''&lt;/p&gt;''.<br />
<br />
Questo è un paragrafo (&lt;p&gt;), 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.<br />
<br />
Quella che inizia con ''<input'' e finisce con ''/>''<br />
<br />
Questa è la riga che fa comparire il pulsante e merita uno sguardo più approfondito. &lt;input&gt; è 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.<br />
<br />
Tanto per intenderci, scrivere<br />
<pre> <input type="button" /><br />
</pre><br />
è 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.<br />
<br />
''id'' l’abbiamo già visto per ''&lt;p&gt;'', mentre la scritta ''value="Premimi per cambiare il testo"'' è quella che fa comparire la relativa scritta sul pulsante, che altrimenti risulterebbe vuoto.<br />
<br />
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?<br />
<br />
Quindi, se vogliamo del codice JavaScript da eseguire a comando, ci basta fare così:<br />
<br />
#creiamo un pulsante HTML (&lt;input type="button"… /&gt;);<br />
#creiamo un codice JavaScript che inizi con la parola ''function'', es: function codiceDaChiamare();<br />
#nell’istruzione &lt;input&gt; aggiungiamo una parte “onclick”, es: onclick="codiceDaChiamare()".<br />
<br />
Fatto.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Il codice JavaScript<br />
<pre> function cambioTesto(){<br />
document.getElementById("testoDaCambiare").innerHTML = "Ecco! Hai visto? Sono cambiato&nbsp;:-)";<br />
}<br />
</pre><br />
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?<br />
<br />
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.<br />
Nello HTML posso scrivere dei paragrafi in un blocco che inizia con<div>e finisce con</div>. In questo modo posso tenere in ordine ciò che scrivo, altrimenti corro il rischio di non capirci più niente.<br />
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.<br />
<br />
L’istruzione<br />
<pre> document.getElementById("testoDaCambiare").innerHTML = "Ecco! Hai visto? Sono cambiato&nbsp;:-)";<br />
</pre><br />
è 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&nbsp;:-)”.<br />
<br />
Facciamo un paragone con ciò che possiamo ottenere con Scratch.<br />
<br />
Mettiamo di scrivere un esempio come il seguente:<br />
<br />
<br/>[[File:C++ Qt 01 Scratch 01 Inizio.jpg|File:C++_Qt_01_Scratch_01_Inizio.jpg]]<br />
<br />
<br/>I blocchi di codice sono semplicemente:<br />
<br />
<br/>[[File:C++ Qt 01 Scratch 01 Inizio blocco1.jpg|File:C++_Qt_01_Scratch_01_Inizio_blocco1.jpg]]<br />
<br />
<br/>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).<br />
<br />
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 {}.<br />
<br />
Vi immaginate di scrivere un programma che non abbia eventi? Ossia dove non ci siano pulsanti da clickare per far capitare delle cose?<br />
<br />
Ebbene, state per farlo! La brutta notizia è che nel C++ nudo e crudo non ci sono pulsanti né eventi.<br />
<br />
=== Si scrive Qt, si legge carino ===<br />
<br />
«Agh!» starete per dire. «Come sarebbe a dire che non ci sono eventi? E come si fa, senza?»<br />
<br />
Tranquilli, era solo per spaventarvi&nbsp;:-)<br />
<br />
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.<br />
<br />
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.<br />
<br />
Ah, dimenticavo: per avere i pulsanti va installato Qt.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Un’ultima cosa: Qt si legge come la parola inglese ''cute'', che vuol dire carino. È voluto.<br />
<br />
=== L’ambiente di programmazione ===<br />
<br />
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++.<br />
<br />
È 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++.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Pensate sia finita qui? Ebbene, no: ci sono altre tre belle cose da dire di Qt:<br />
<br />
#La versione base è gratis.<br />
#Quando si installa Qt, automaticamente si installa anche un compilatore, risparmiandoci un bel po’ di lavoro.<br />
#Esiste una versione di Qt per ogni piattaforma: Windows, Linux 32 bit, Linux 64 bit, Mac.<br />
<br />
Ciò significa che non abbiamo bisogno di altro che Qt per cominciare a lavorare.<br />
<br />
Per quei pochi che ancora non si fossero informati&nbsp;;-) Qt si trova qui: <a href="[http://qt-project.org/ http://qt-project.org/]">[http://qt-project.org/ http://qt-project.org/]&lt;/a&gt;<br />
<br />
Ricordatevi che non ci bastano le librerie, vogliamo l’ambiente integrato di sviluppo, ossia '''Qt Creator'''.<br />
<br />
=== L’installazione di Qt ===<br />
<br />
L’installazione di Qt di solito non dà problemi; comunque sia è un argomento che esula da questo tutorial. Qui aggiungo solo delle note.<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
I nomi degli installer somigliano a questi:<br />
<br />
*Per Windows: qt-opensource-windows-x86-1.6.0-5-online.exe<br />
*Per Linux 32 bit: qt-opensource-linux-x86-1.6.0-5-online.run<br />
*Per Linux 64 bit: qt-opensource-linux-x64-1.6.0-5-online.run<br />
*Per Mac: qt-opensource-mac-x64-1.6.0-5-online.dmg<br />
<br />
Ripeto: con i file elencati sopra per installare Qt dovete essere collegati a Internet per tutta la fase di installazione.<br />
<br />
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.<br />
<br />
Le prossime puntate di questo tutorial partiranno dal presupposto che si sia riusciti a installare Qt Creator.<br />
<br />
= Tutorial C++ e Qt: partiamo con calma =<br />
<br />
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.<br />
<br />
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.<br />
<br />
<br/>[[File:Qt appena aperto.png|File:Qt_appena_aperto.png]]<br />
<br />
<br/>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.<br />
<br />
Se ci si fa caso, adesso è selezionata la casella Welcome. Torneremo su questo fra poco.<br />
<br />
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.<br />
<br />
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.<br />
<br />
D’ora innanzi partirò dal presupposto che i nostri file vengano salvati in<br />
<br />
…Documents/ProgrammiCpp/CppQt ma voi chiamate pure le cartelle come volete, non fa nessuna differenza.<br />
<br />
<br/>Torniamo ora a Qt perché è il momento di iniziare a programmare.<br />
<br />
Qt Creator è pensato per aiutarci a scrivere in C++, ma perché possa esserci utile dobbiamo spiegargli cosa vogliamo fare.<br />
<br />
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.<br />
<br />
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).<br />
<br />
Si aprirà una finestra per la creazione dei progetti:<br />
<br />
<br/>[[File:Qt nuovo progetto.png|File:Qt_nuovo_progetto.png]]<br />
<br />
<br/>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.<br />
<br />
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:<br />
<br />
<br/>[[File:Qt Plain C++ Project.png|File:Qt_Plain_C++_Project.png]]<br />
<br />
<br/>Facciamo click su Choose…<br />
<br />
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.<br />
<br />
<br/>[[File:Qt Saluto.png|File:Qt_Saluto.png]]<br />
<br />
<br/>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.<br />
<br />
Come vedete è comparsa una nuova cartella, ''Saluto''. Bene, i nostri file relativi a questo progetto dovranno essere salvati tutti in quella cartella.<br />
<br />
Con questa osservazione è ora di farla finita con Qt e di parlare finalmente del C++.<br />
<br />
<br />
<br />
== Ciao, mondo! ==<br />
<br />
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.<br />
<br />
Vediamo un po’ cosa ci troviamo davanti. Dovrebbe essere una schermata su per giù come questa:<br />
<br />
<br/>[[File:Qt CiaoMondo.png|File:Qt_CiaoMondo.png]]<br />
<br />
<br/>Beh, qui ci aspetta un’amara sorpresa: Qt Creator, senza nemmeno chiedercelo, ha già scritto tutto il codice al posto nostro!<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Intanto vediamo se il codice è corretto e funziona oppure se Qt ci ha fregato. Compiliamo subito questo programma e mandiamolo in esecuzione.<br />
<br />
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.<br />
<br />
<br/>[[File:Qt CiaoMondo Esegui.png|File:Qt_CiaoMondo_Esegui.png]]<br />
<br />
<br/>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ì:<br />
<br />
<br/>[[File:Qt CiaoMondo ris 1.png|File:Qt_CiaoMondo_ris_1.png]]<br />
<br />
<br/>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.<br />
<br />
<br />
<br />
== Ehi, avevamo detto “Ciao, mondo!” ==<br />
<br />
È 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.<br />
<br />
Intanto, come da istruzioni, chiudiamo la finestrella che si è aperta (ricordiamoci di farlo sempre!).<br />
<br />
Poi andiamo nel nostro codice e troviamo la seguente riga:<br />
<pre> cout << "Hello World!" << endl;<br />
</pre><br />
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ì:<br />
<pre> cout << "Ciao, mondo!" << endl;<br />
</pre><br />
A questo punto facciamo di nuovo click sull’icona a forma di triangolo verde e vediamo il risultato.<br />
<br />
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.<br />
<br />
Bene, chiudiamo anche la nuova finestra che si è aperta e diamo un’occhiata al nostro programma.<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
<br />
{<br />
<br />
cout << "Ciao, mondo!" << endl;<br />
return 0;<br />
<br />
}<br />
</pre><br />
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?<br />
<br />
Esatto, è proprio così: in entrambi i casi c’è un nome seguito da una parentesi aperta e una chiusa:<br />
<pre>nome()</pre><br />
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!<br />
<br />
Ma vi ricordate cos’è una funzione? Diciamolo in modo semplice:<br />
<br />
Una funzione è un blocco di codice che inizia con una parentesi graffa aperta { e finisce con una parentesi graffa chiusa }.<br />
<br />
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.<br />
<br />
Confrontiamo i due blocchi di codice:<br />
<br />
<br />
<br />
{| class="wikitable"<br />
|-<br />
! <center>JavaScript</center><br />
! <center>C++</center><br />
|-<br />
| function cambioTesto(){<br />
| int main() {<br />
|}<br />
<br />
Le uniche differenze che ci vedo io sono:<br />
<br />
#la scritta ''function'' nel JavaScript (che non c’è nel C++);<br />
#la scritta ''int'' nel C++ (che non c’è nel JavaScript).<br />
<br />
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<br />
<pre>int main() {<br />
cout << "Ciao, mondo!" << endl;<br />
</pre><br />
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.<br />
<br />
Diamo un’occhiata alle altre due differenze.<br />
<br />
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''.<br />
<br />
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.<br />
<br />
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''?<br />
<pre>int ciaoMondo()</pre><br />
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.<br />
<br />
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.<br />
<br />
Lo stesso principio vale per il C++: il codice da ‘eseguire’ è quello che comincia con ''main''.<br />
<br />
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.<br />
<br />
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''.<br />
<br />
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.<br />
<br />
== Blocchi dappertutto ==<br />
<br />
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.<br />
<br />
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.<br />
<pre> cout << "Ciao, mondo!" << endl;</pre><br />
''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.<br />
<br />
Ossia, se volete comunicare qualcosa a chi sta usando il programma e decidete di comunicarlo facendolo comparire a schermo, vi basta scrivere:<br />
<pre> cout << "Ehi, utente di questo programma, ti volevo dire che...";</pre><br />
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.<br />
<br />
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.<br />
<br />
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!):<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
cout << "Ciao, mondo!";<br />
cout << "Sono a fare un po' di esperimenti con il C++";<br />
<br />
return 0;<br />
}<br />
</pre><br />
E mandiamolo in esecuzione facendo click sulla freccia verde – anzi, chi vuole può sperimentare un altro metodo: CTRL + R.<br />
<br />
Ricordatevi che, se non avete salvato, Qt prima di compilare vi chiede se volete salvare.<br />
<br />
A me compare la seguente finestra:<br />
<br />
[[File:Qt CiaoMondo ris 2.png|File:Qt_CiaoMondo_ris_2.png]]<br />
<br />
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:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
cout << "Ciao, mondo!" << endl;<br />
cout << "Sono a fare un po' di esperimenti con il C++" << endl << endl;<br />
<br />
return 0;<br />
}<br />
</pre><br />
Il risultato è molto più leggibile:<br />
<br />
[[File:Qt CiaoMondo ris 3.png|File:Qt_CiaoMondo_ris_3.png]]<br />
<br />
<br/>L’esempio mi sembra non richieda spiegazioni, però servono due note:<br />
<br />
*''cout'' si pronuncia in inglese come se fosse scritto c-out, quindi in italiano suona all’incirca si-aut.<br />
*''endl'' è la fusione delle parole inglesi ''end'' e ''line'', perciò non c’è nulla di male a pronunciarlo ''endline'' – ‘endlain’.<br />
<br />
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?<br />
<br />
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.<br />
<br />
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?<br />
<br />
Semplice: glielo abbiamo detto noi&nbsp;:-)<br />
<br />
Sorpresi? Il trucco è semplice: la prima riga del nostro programma recita:<br />
<pre>#include <iostream></pre><br />
''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''.<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
A questo punto abbiamo visto quasi tutto, il resto è molto astratto e ne faremo solo un accenno, per ora:<br />
<br />
{| class="wikitable"<br />
|-<br />
! <center>Codice</center><br />
! <center>Cosa fa il compilatore</center><br />
|-<br />
| #include &lt;iostream&gt;<br />
| copia-incolla il contenuto del file ''iostream'' al posto di questo rigo<br />
|-<br />
| using namespace std;<br />
| 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<br />
|-<br />
| int main() {<br />
| definisco una funzione che si chiama ''main''. ''main'' è obbligatoria in un programma C++<br />
|-<br />
| cout…<br />
| già visto<br />
|-<br />
| return 0;<br />
| questo lo vediamo tra poco<br />
|-<br />
| <nowiki> } </nowiki><br />
| fine della funzione ''main''. Quando si esce da ''main'' il programma finisce.<br />
|}<br />
<br />
= Tutorial C++ e Qt: la nostra prima funzione =<br />
<br />
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.<br />
<br />
Immaginiamo di voler scrivere l’equivalente C++ del seguente programma Scratch:<br />
<br />
<br/>[[File:C++ Qt 01 Scratch 02.png|File:C++_Qt_01_Scratch_02.png]]<br />
<br />
<br/>Immaginiamocelo prima in JavaScript.<br />
<pre><!DOCTYPE html><br />
<br />
<html lang="it-IT"><br />
<head><br />
<meta charset="utf-8"><br />
<br />
<title>JavaScript e HTML5 - un pulsante che saluta</title><br />
<br />
<script type="text/javascript"><br />
function cambioTesto(){<br />
var utente = document.getElementById("risposta").value;<br />
document.getElementById("testoDaCambiare").innerHTML = "Ciao, " + utente + "!";<br />
}<br />
</script><br />
</head><br />
<br />
<body><br />
<div><br />
<label for="risposta">Qual è il tuo nome?</label><br />
<input type="text" id="risposta" /><br />
</div><br />
<div><br />
<label for="cambiaTesto">Pulsante che modificherà il testo sottostante --></label><br />
<input type="button" id="cambiaTesto" value="Premimi per cambiare il testo"<br />
onclick="cambioTesto();" /><br />
</div><br />
<div><br />
<p>Il testo contenuto in questo paragrafo cambierà quando sarà premuto il pulsante soprastante.</p><br />
</div><br />
</body><br />
</html><br />
</pre><br />
Il programma è molto simile al precedente e credo che da spiegare ci sia solo la piccola modifica alla funzione ''cambioTesto()''. In modo molto schematico:<br />
<br />
'''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''.<br />
<br />
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.»<br />
<br />
<br/>'''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).»<br />
<br />
<br/>'''var utente = document.getElementById("risposta").value;'''<br />
<br />
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”.<br />
<br />
<br/>'''document.getElementById("testoDaCambiare").innerHTML = "Ciao, " + nome + "!";'''<br />
<br />
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.<br />
<br />
<br/>'''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).<br />
<br />
<br />
<br />
== O scriviamolo in C++, perdindirindina ==<br />
<br />
Ecco come viene il programma in C++:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
string utente;<br />
<br />
cout << "Qual è il tuo nome? ";<br />
<br />
cin >> utente;<br />
<br />
cout << "Ciao, " << utente << "!" << endl << endl;<br />
<br />
return 0;<br />
}<br />
</pre><br />
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.<br />
<br />
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.<br />
<br />
<br/>'''string utente;'''<br />
<br />
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''.<br />
<br />
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.<br />
<br />
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 è!&nbsp;:-) 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:<br />
<pre> int numeriinteri;<br />
</pre><br />
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ì:<br />
<pre> int quiCiMettoDelTesto;<br />
</pre><br />
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).<br />
<br />
Quindi l’istruzione:<br />
<pre> quiCiMettoDelTesto = 6;<br />
</pre><br />
andrà a buon fine, mentre l’istruzione:<br />
<pre> quiCiMettoDelTesto = "Mario";<br />
</pre><br />
sarà bloccata dal compilatore.<br />
<br />
Se vi domandate cosa succede quando si scrive qualcosa su cui il compilatore non è… d’accordo, la risposta è: provate!&nbsp;:-) 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.<br />
<br />
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.<br />
<br />
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 ''<nowiki>#include</nowiki>'' nel nostro codice? Beh, questo già fornisce la risposta&nbsp;;-) 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:<br />
<pre>#include <string><br />
</pre><br />
'''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.<br />
<br />
<br/>'''cin >> utente;'''<br />
<br />
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!<br />
<br />
<br/>'''cout << "Ciao, " << utente << "!" << endl << endl;'''<br />
<br />
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.»<br />
<br />
<br />
<br />
== Sì, ma senza funzioni non funziona! ==<br />
<br />
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:<br />
<pre>#include <iostream><br />
using namespace std;<br />
</pre><br />
Queste due istruzioni non sono all’interno di nessun blocco.<br />
<br />
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++.<br />
<br />
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:<br />
<br />
<head> … </head><br />
<body> … </body><br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
L’istruzione ''<nowiki>#include <iostream></nowiki>'' è 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.<br />
<br />
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.<br />
<br />
<br />
<br />
=== Ordine e pulizia ===<br />
<br />
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.<br />
<br />
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++».<br />
<pre> // Questo è solo un promemoria, una nota, un commento.<br />
// Il compilatore ignorerà queste righe.<br />
</pre><br />
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.<br />
<br />
Ossia, ''main'' dovrà diventare così:<br />
<pre>int main()<br />
{<br />
*** faccio partire la funzione che chiede il nome all’utente e lo saluta ***<br />
return 0;<br />
}<br />
</pre><br />
Tutto il lavoro lo farà un’altra funzione, di cui dobbiamo decidere il nome. Che ne dite di ''salutaUtente''?<br />
<br />
Ecco la nostra funzione:<br />
<pre>void salutaUtente()<br />
{<br />
string utente;<br />
<br />
cout << "Qual è il tuo nome? ";<br />
<br />
cin >> utente;<br />
<br />
cout << "Ciao, " << utente << "!" << endl << endl;<br />
}<br />
</pre><br />
La riconoscete? È esattamente ciò che era contenuto nella funzione ''main'': l’ho solo spostato.<br />
<br />
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!<br />
<br />
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à:<br />
<pre> salutaUtente();<br />
</pre><br />
A questo punto ecco il nostro codice completo:<br />
<br />
<br />
<pre>#include <iostream><br />
<br />
void salutaUtente();<br />
<br />
using namespace std;<br />
<br />
int main()<br />
{<br />
salutaUtente();<br />
return 0;<br />
}<br />
<br />
void salutaUtente()<br />
{<br />
string utente;<br />
<br />
cout << "Qual è il tuo nome? ";<br />
<br />
cin >> utente;<br />
<br />
cout << "Ciao, " << utente << "!" << endl << endl;<br />
}<br />
</pre><br />
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ù.<br />
<br />
Se avete qualche dubbio, ecco come viene la schermata di Qt Creator:<br />
<br />
[[File:Qt CiaoMondo 4.png|File:Qt_CiaoMondo_4.png]]<br />
<br />
È andato tutto bene? Avete ricevuto qualche messaggio di errore?<br />
<br />
Se non avete ricevuto alcun messaggio di errore ci sono 2 possibilità:<br />
<br />
#siete stati molto attenti e precisi;<br />
#avete fatto il copia-incolla&nbsp;:-)<br />
<br />
Nel codice è infatti spuntata una riga di cui non vi avevo accennato, la numero 3:<br />
<pre>void salutaUtente();<br />
</pre><br />
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):<br />
<pre>void salutaUtente()<br />
{<br />
</pre><br />
Che cos’è questo duplicato? '''E come mai si trova fuori da un blocco?!'''<br />
<br />
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.»<br />
<br />
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''.<br />
<br />
PATATRACK!<br />
<br />
Il programma non funzionerà mai.<br />
<br />
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.<br />
<br />
In realtà l’argomento è molto più complesso, ma per trattarlo dovremmo introdurre il concetto di ''spazio di visibilità'', cosa che faremo tra poco.<br />
<br />
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();''?»<br />
<br />
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.<br />
<br />
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.<br />
<br />
<br/>Andiamo avanti con le osservazioni. Paragonate queste due righe, che aprono entrambe una funzione:<br />
<br />
rigo 7 → int main()<br/>rigo 13 → void salutaUtente()<br />
<br />
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''?<br />
<br />
Continuando a osservare, scopriamo che in ''main'' c’è un’istruzione misteriosa che in ''salutaUtente'' non c’è:<br />
<pre> return 0;<br />
</pre><br />
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:<br />
<br />
*'''int''' main ↔ return 0;<br />
*'''void''' salutaUtente ↔ nessuna istruzione return.<br />
<br />
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'':<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
string salutaUtente();<br />
<br />
int main()<br />
{<br />
string nome_utente;<br />
nome_utente = salutaUtente();<br />
<br />
cout << "Ciao, " << nome_utente << "!" << endl << endl;<br />
<br />
return 0;<br />
}<br />
<br />
string salutaUtente()<br />
{<br />
string utente;<br />
<br />
cout << "Qual è il tuo nome? ";<br />
<br />
cin >> utente;<br />
<br />
return utente;<br />
}<br />
</pre><br />
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’.<br />
<br />
Il programma fa sempre la stessa cosa, però, guardate un po’:<br />
<br />
*'''void''' salutaUtente() è diventata '''string''' salutaUtente()<br />
*alla fine di salutaUtente c’è un ''return utente;''… e per l’appunto la variabile ‘utente’ è definita di tipo '''''string'''''!<br />
<br />
E poi in main è comparsa la misteriosa riga:<br />
<pre>nome_utente = salutaUtente();<br />
</pre><br />
che riguarda, ancora una volta, una variabile che è stata definita di tipo '''''string''''' nel rigo precedente;<br />
<br />
Saranno tutte coincidenze? Beh, no, è chiaro. Rilassatevi, è il momento della spiegazione.<br />
<br />
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.<br />
<br />
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.<br />
<br />
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?<br />
<br />
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'''.<br />
<br />
Questo può essere davvero comodo, e il bello è che ottenere questo risultato è semplicissimo: basta usare la parola chiave ''return''.<br />
<br />
Mettiamo di scrivere una funzione che finisca con queste righe:<br />
<pre> return 14;<br />
}<br />
</pre><br />
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:<br />
<pre> return true;<br />
</pre><br />
oppure come questa:<br />
<pre> return false;<br />
</pre><br />
Adesso guardiamo passo passo cosa fa il nostro nuovo programma, iniziando direttamente da ''main''.<br />
<br />
<br/>'''int main()''' Entro nella funzione ''main'' e inizio con l’eseguire queste istruzioni.<br />
<br />
<br/>'''string nome_utente;''' Creo una variabile. Scelgo come nome ‘nome_utente’ e decido che debba essere idonea a contenere del testo (''string'').<br />
<br />
<br/>'''nome_utente = salutaUtente();''' Inserisco un valore nella variabile ‘nome_utente’. Anche se l’istruzione può sembrare strana, è assolutamente identica a scrivere una cosa tipo:<br />
<pre> nome_utente = "Non mi viene in mente nessun nome...";<br />
</pre><br />
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''».<br />
<br />
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'':<br />
<br />
<br/>'''string utente;''' Creo una variabile. Decido che debba essere idonea a contenere, come tipo di dati, del testo. Decido di chiamarla ‘utente’.<br />
<br />
<br/>'''cout << "Qual è il tuo nome? ";''' Scrivo sullo schermo: Qual è il tuo nome?<br />
<br />
<br/>'''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'').<br />
<br />
<br/>'''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'').<br />
<br />
<br/>'''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.<br />
<br />
<br/>'''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”.<br />
<br />
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&nbsp;:-)<br />
<br />
Prima di iniziare questa nuova fatica di Sisifo, diamo un attimo un’occhiata a questo banale progettino di Scratch:<br />
<br />
[[File:C++ Qt 01 Scratch 03.png|File:C++_Qt_01_Scratch_03.png]]<br />
<br />
<br/>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.<br />
<br />
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?<br />
<br />
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:<br />
<br />
*se in inglese si dice if;<br />
*altrimenti in inglese si dice else.<br />
<br />
In C++ scriveremo qualcosa così:<br />
<pre> if (condizione)<br />
<br />
{<br />
cose da fare se la condizione è vera;<br />
}<br />
<br />
else<br />
<br />
{<br />
cose da fare se la condizione è falsa;<br />
}<br />
</pre><br />
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.<br />
<br />
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''.<br />
<br />
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&nbsp;:<br />
<pre> if (condizione) {<br />
cose da fare se la condizione è vera;<br />
}<br />
else {<br />
cose da fare se la condizione è falsa;<br />
}<br />
</pre><br />
o addirittura a:<br />
<pre> if (condizione) {<br />
cose da fare se la condizione è vera;<br />
} else {<br />
cose da fare se la condizione è falsa;<br />
}<br />
</pre><br />
È 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 ''if''…''else''.<br />
<br />
Eccolo qua:<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int salutaUtente(string nome_utente);<br />
int interrogaUtente();<br />
<br />
int main()<br />
{<br />
int messaggio_per_il_sistema_operativo;<br />
messaggio_per_il_sistema_operativo = interrogaUtente();<br />
<br />
return messaggio_per_il_sistema_operativo;<br />
}<br />
<br />
int interrogaUtente()<br />
{<br />
string utente;<br />
<br />
cout << "Qual è il tuo nome? ";<br />
cin >> utente;<br />
<br />
int verifica;<br />
verifica = salutaUtente(utente);<br />
<br />
if ( verifica == -1 ) {<br />
cout << "Con te non ci parlo più." << endl << endl;<br />
}<br />
<br />
return verifica;<br />
}<br />
<br />
int salutaUtente(string nome_utente)<br />
{<br />
int segnale_di_ritorno;<br />
<br />
if ( nome_utente.length() < 3 ) {<br />
cout << "Hai scritto solo le iniziali!" << endl;<br />
segnale_di_ritorno = -1;<br />
}<br />
<br />
else {<br />
cout << "Ciao, " << nome_utente << "!" << endl << endl;<br />
segnale_di_ritorno = 0;<br />
}<br />
<br />
return segnale_di_ritorno;<br />
}<br />
</pre><br />
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ù!<br />
<br />
<br/>[[File:Qt CiaoMondo 5.png|File:Qt_CiaoMondo_5.png]]<br />
<br />
<br/>Vediamo un po’ che sorprese ci riserva questo codice.<br />
<br />
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''.<br />
<br />
''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.<br />
<br />
A questo punto:<br />
<br />
'''string utente;''' → l’abbiamo già vista.<br />
<br />
'''cout << "Qual è il tuo nome? ";''' → l’abbiamo già vista.<br />
<br />
'''cin >> utente;''' → l’abbiamo già vista.<br />
<br />
'''int verifica;''' → dovrebbe ormai essere chiara.<br />
<br />
'''verifica = salutaUtente(utente);'''<br />
<br />
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''.»<br />
<br />
Questo l’abbiamo già visto, ma è la parola utente scritta dopo ''salutaUtente'' che rappresenta una novità.<br />
<br />
Ripensiamo a quello che abbiamo fatto:<br />
<br />
#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…'').<br />
#Poi abbiamo introdotto delle funzioni che dialogavano con il codice circostante, rimandando indietro un segnale di ritorno (''return…'').<br />
#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.<br />
<br />
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»?<br />
<br />
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:<br />
<br />
*cos’è che dovete fare (mettere quelle buste nelle rispettive cassette);<br />
*i dati per farlo (gli indirizzi che sono scritti sulle buste).<br />
<br />
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».<br />
<br />
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.<br />
<br />
Il trucco sta nell’informare la funzione di quali dati deve ''ricevere'' e di quali deve ''restituire''.<br />
<br />
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.<br />
<br />
Quindi, una funzione che inizia così:<br />
<pre> int nomeacaso (string nome_di_una_variabile)<br />
</pre><br />
accetterà una variabile di tipo ''string'' in ingresso e restituirà un segnale di ritorno di tipo ''int''.<br />
<br />
Adesso guardiamo come inizia ''salutaUtente'':<br />
<pre>int salutaUtente(string nome_utente)<br />
</pre><br />
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.»<br />
<br />
A questo punto siamo entrati nella funzione ''salutaUtente'' e le prossime righe che saranno eseguite saranno:<br />
<br />
'''int segnale_di_ritorno;''' → questa è chiara, ormai, no?<br />
<br />
'''if ( nome_utente.length() < 3 ) {'''<br />
<br />
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:<br />
<pre> int salutaUtente(string nome_utente)<br />
</pre><br />
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:<br />
<pre> int salutaUtente()<br />
{<br />
string nome_utente;<br />
</pre><br />
avremmo ottenuto esattamente la stessa variabile.<br />
<br />
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.<br />
<br />
Ossia, già prima di entrare dentro la funzione ''salutaUtente'', si è verificato questo fatto:<br />
<br />
‘nome_utente’ di ''salutaUtente'' = ‘utente’ di ''interrogaUtente''.<br />
<br />
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’.<br />
<br />
Quindi noi stiamo usando ‘nome_utente’ che contiene una COPIA di ciò che l’utente ha digitato sulla tastiera.<br />
<br />
Ciò che noi vogliamo fare è:<br />
<br />
#controlliamo quanti caratteri ci sono nella variabile ‘nome_utente’;<br />
#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&nbsp;:-) Quindi, mandiamo un messaggio di protesta.<br />
#Se invece i caratteri sono almeno 3, che potrebbe essere vero per “Ugo”, allora salutiamo l’utente come abbiamo fatto fin’ora.<br />
<br />
Vediamo di capire come funziona quanto sopra in C++.<br />
<br />
''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.<br />
<br />
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.<br />
<br />
In conclusione: il significato di questa riga è: «Se la lunghezza di ‘nome_utente’ è inferiore a 3 (caratteri), allora…»<br />
<br />
'''cout << "Hai scritto solo le iniziali!" << endl;''' → questo dovrebbe essere chiaro.<br />
<br />
'''segnale_di_ritorno = -1;'''<br />
<br />
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.<br />
<br />
'''else {''' → altrimenti…<br />
<br />
'''cout << "Ciao, " << nome_utente << "!" << endl << endl;''' → già visto.<br />
<br />
'''segnale_di_ritorno = 0;''' → il contenuto di ‘segnale_di_ritorno’ deve essere 0.<br />
<br />
'''return segnale_di_ritorno;'''<br />
<br />
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!”.<br />
<br />
A questo punto il computer ritorna in ''interrogaUtente'' ed esegue:<br />
<br />
'''if ( verifica == -1 ) {''' «Se ''salutaUtente'' ha restituito -1, allora…»<br />
<br />
'''cout << "Con te non ci parlo più." << endl << endl;''' → penso sia chiaro.<br />
<br />
'''return verifica;'''<br />
<br />
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''.<br />
<br />
Siamo ormai tornati in ''main'' e la prossima riga ad essere eseguita sarà:<br />
<br />
'''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.<br />
<br />
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:<br />
<br />
[[File:Qt CiaoMondo 5 freccette.png|File:Qt_CiaoMondo_5_freccette.png]]<br />
<br />
<br />
<br />
=== Come farsi odiare ===<br />
<br />
Bene, non credo che questo programmino possa darci molto di più.<br />
<br />
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.<br />
<br />
Avremmo anche potuto scrivere:<br />
<pre>int salutaUtente(string nome_utente)<br />
{<br />
int segnale_di_ritorno;<br />
<br />
int lunghezza = nome_utente.length(); // Questa riga non c'era<br />
<br />
if ( lunghezza < 3 ) { // Questa riga è un po' diversa<br />
cout << "Hai scritto solo le iniziali!" << endl;<br />
segnale_di_ritorno = -1;<br />
}<br />
<br />
else {<br />
cout << "Ciao, " << nome_utente << "!" << endl << endl;<br />
segnale_di_ritorno = 0;<br />
}<br />
<br />
return segnale_di_ritorno;<br />
}<br />
</pre><br />
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à!<br />
<br />
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.<br />
<br />
Vi avverto che, pur sapendo perfettamente cosa fa, leggerlo può risultare un po’ complicato!<br />
<pre>#include <iostream><br />
<br />
using namespace std;<br />
<br />
int salutaUtente(string nome_utente);<br />
int interrogaUtente();<br />
<br />
int main()<br />
{<br />
return interrogaUtente();<br />
}<br />
<br />
int interrogaUtente()<br />
{<br />
string utente;<br />
cout << "Qual è il tuo nome? ";<br />
cin >> utente;<br />
<br />
int verifica = salutaUtente(utente);<br />
if ( verifica == -1 ) {<br />
cout << "Con te non ci parlo più." << endl << endl;<br />
}<br />
<br />
return verifica;<br />
}<br />
<br />
int salutaUtente(string nome_utente)<br />
{<br />
int segnale_di_ritorno = 0;<br />
<br />
if ( nome_utente.length() < 3 ) {<br />
cout << "Hai scritto solo le iniziali!" << endl;<br />
segnale_di_ritorno = -1;<br />
}<br />
else {<br />
cout << "Ciao, " << nome_utente << "!" << endl << endl;<br />
}<br />
<br />
return segnale_di_ritorno;<br />
}<br />
</pre> [[Category:C++|Category:C++]]</div>
Robi
https://kata.coderdojo.it/wiki/index.php?title=Tutorial:_Mostro_Mangia_Palla
Tutorial: Mostro Mangia Palla
2014-10-16T21:44:10Z
<p>Fpiantini: </p>
<hr />
<div>== Gioco Mostro Mangia Palla ==<br />
<br />
L'obiettivo del gioco è quello di far mangiare al mostro più palle possibile in un periodo di tempo prederminato. Il mostro viene controllato tramite lo spostamento del mouse.<br />
<br />
Con questo gioco si dimostra come gestire in modo elementare il movimento di uno sprite e come gestire l'interazione tra sprite diversi. Viene inoltre dimostrato l'uso del cronometro e dei segnali per far comunicare tra di loro diverse componenti del gioco.<br />
<br />
Il gioco può essere scaricato dall'archivio kata sia nella versione [http://kata.coderdojo.it/archivio/MostroInseguePallaconMouse.sb base] che nella versione [http://kata.coderdojo.it/archivio/MostroInseguePallaconMouse2.sb avanzata] descritta in appendice.<br />
<br />
=== Passo 1: Creazione dello sprite mostro, algoritmo di movimento ===<br />
<br />
Tramite il bottone "Seleziona nuovo sprite da file" scegliere il protagonista del gioco dalla galleria di personaggi messa a disposizione dal programma. Sono particolarmente indicati i personaggi della sezione Fantasy.<br />
<br />
[[File:000 nuovo sprite da file.png|File:000_nuovo_sprite_da_file.png]]<br />
<br />
Ricordarsi che il mostro deve essere lasciato libreo di ruotare.<br />
<br />
Si può passare quindi subito a realizzare lo script di movimento del mostro: un semplice programma che insegue costantemente il mouse e si ferma quando lo raggiunge.<br />
<br />
[[File:001 script movimento mostro.png|File:001_script_movimento_mostro.png]]<br />
<br />
Da notare che l'istruzione "porta dimensione al 50%" potrebbe non essere necessaria o potrebbe avere bisogno di essere impostata a una percentuale diversa a seconda della dimensione del personaggio scelto.<br />
<br />
=== Passo 2: Preparazione degli sfondi dello stage ===<br />
<br />
Lo stage è costituito da due sfondi: il principale '''sfondo1''' vuoto è quello che viene mostrato durante il gioco, il secondo ('''sfondo2''') appare alla fine del gioco allo scadere del cronometro per indicare lo stato di partita terminata.<br />
<br />
Come '''sfondo1''' si può utilizzare quello bianco che è presente di default, occorre quindi realizzare solo '''sfondo2''', tramite i seguenti passi:<br />
<br />
*Andare nella sezione sfondi e duplicare lo sfondo presente tramite il pulsante '''Copia'''<br />
<br />
[[File:003 crea e modifica sfondo.png|File:003_crea_e_modifica_sfondo.png]]<br />
<br />
*Modificare lo sfondo a piacimento, l'importante è che si legga chiaramente una scritta con indicata la condizione di fine gioco (Game Over)<br />
<br />
[[File:004 sfondo game over.png|File:004_sfondo_game_over.png]]<br />
<br />
Dare al secondo sfondo il nome '''fine'''<br />
<br />
=== Passo 2: Script per lo stage, variabile punti e cronometro ===<br />
<br />
Adesso che gli sfondi sono pronti, si può passare alla scrittura dello script.<br />
<br />
Per prima cosa occorre introdurre una nuova variabile di nome '''punti'''. Per fare questo si va nella sezione arancione '''Variabili''' e si clicca su nuova variabile:<br />
<br />
[[File:005 creazione nuova variabile.png|File:005_creazione_nuova_variabile.png]]<br />
<br />
Si può passare quindi alla scrittura dello script vero e proprio. All'avvio si inizializza la variabile a zero e si fa partire il cronometro. Successivamente si entra in un loop "per sempre" e si aspetta che il cronometro abbia superato una soglia (per esempio 30 secondi). Allo scadere del cronometro si invia un segnale di STOP a tutti, si passa allo sfondo '''fine''' e si ferma il programma.<br />
<br />
[[File:006 script stage.png|File:006_script_stage.png]]<br />
<br />
In questa porzione di codice si capisce come funzionano i segnali, concetto che merita di essere descritto bene dal mentor per far capire come sia possibile far comunicare tra di loro componenti diversi del programma. Nel nostro caso, la generazione del segnale STOP viene fatta per far scomparire dallo schermo gli sprite alla fine del gioco. Per realizzare l'operazione per lo sprite già realizzato (il mostro) è quindi sufficiente aggiungere le seguenti linee nella sezione script dello sprite Mostro:<br />
<br />
[[File:007 stop nascondi.png|File:007_stop_nascondi.png]]<br />
<br />
=== Passo 3: la prima palla ===<br />
<br />
L'obiettivo del gioco è far mangiare al mostro quante più palle possibile. Nella versione iniziale del gioco si utilizzano due palle. Prima si realizza il programma completo per una, dopo sarà sufficiente copiarlo sulla seconda. Lo script della palla prevede di farla apparire in una posizione casuale e ogni tanto spostarla. Quando il mostro la tocca, la palla sparisce (viene "mangiata"), per riapparire più tardi in un'altra posizione casuale. Ogni volta che una palla viene mangiata la variabile globale '''punti''' viene incrementata di uno. Anche gli sprite che raffigurano le palle devono sparire dallo schermo alla fine del gioco; questa cosa viene ottenuta esattamente come per lo sprite del mostro tramite la gestione del segnale STOP.<br />
<br />
Per creare uno sprite palla scegliere sempre il pulsante "Seleziona nuovo sprite da file" e selezionare un tipo di palla nella sezione "Things" delle immagini predefinite del programma.<br />
<br />
Lo script completo per una palla è il seguente.<br />
<br />
[[File:008 script per sprite palla.png|File:008_script_per_sprite_palla.png]]<br />
<br />
'''NOTA:''' per rendere più divertente il gioco, si fa produrre un suono alla palla tutte le volte che viene mangiata. Per poterlo fare è necessario prima associare un suono allo sprite. Per fare questo si può importare un suono preesistente tramite il tasto '''Importa''' presente nella sezione '''Suoni''' dello sprite oppure, se il computer lo permette se ne può far registrare uno direttamente al bambino tramite il tasto '''Registra'''.<br />
<br />
=== Passo 4: la seconda palla ===<br />
<br />
Per creare la seconda palla si segue la stessa procedura utilizzata per la prima (scegliendo magari un'immagine diversa). Siccome la seconda palla si deve comportare esattamente come la prima si copia il programma scritto per la prima semplicemente trascinandolo le varie componenti dello script sopra lo sprite della seconda palla.<br />
<br />
<br />
<br />
=== Appendice: esercizi e estensione del gioco ===<br />
<br />
Come esercizio si possone realizzare le seguenti estensioni del gioco:<br />
<br />
*Introdurre un sprite che ostacoli il movimento del mostro. Anche questo sprite si posiziona sullo schermo casualmente come le palle. Il contatto con questo elemento fa però perdere punti al mostro e ne ostacola il movimento<br />
*Fare un maggior uso dei messaggi<br />
*Introdurre una variabile '''tempo''' per mostrare quanto tempo manca al termine del gioco.<br />
<br />
'''Versione estesa: script dello stage:'''<br />
<br />
[[File:012 script stage versione evoluta.png|File:012_script_stage_versione_evoluta.png]]<br />
<br />
'''Versione estesa: script del mostro:'''<br />
<br />
[[File:009 mostro script versione evoluta.png|File:009_mostro_script_versione_evoluta.png]]<br />
<br />
'''Versione estesa: script della palla:'''<br />
<br />
[[File:010 script palla versione evoluta.png|File:010_script_palla_versione_evoluta.png]]<br />
<br />
'''Versione estesa: script dell'ostacolo:'''<br />
<br />
[[File:011 script ostacolo.png|File:011_script_ostacolo.png]]<br />
[[Category:Scratch|M]]</div>
Fpiantini
https://kata.coderdojo.it/wiki/index.php?title=Tutorial:_Spara_ai_palloncini
Tutorial: Spara ai palloncini
2014-09-21T17:37:28Z
<p>Leoncino: </p>
<hr />
<div>== Gioco Spara ai Palloncini (mentor) ==<br />
<br />
In questo gioco si fanno apparire dei palloncini dal basso e si fanno esplodere cliccandoci sopra con il mouse. La versione completa del gioco è scaricabile [http://kata.coderdojo.it/archivio/palloncini.sb dall'archivio]<br />
<br />
Si parte con uno sprite che rappresenta un palloncino con due (o più) costumi per l'animazione (si fa un ovale colorato e un cordino nero in due posizioni), e uno per quando viene colpito come si vede dall'immagine seguente:<br />
<br />
<br/>[[File:Palloncini.png|center|Palloncini.png]]<br />
<br />
<br/>Dopodiché si passa al mirino, basta fare una croce che segue il puntatore del mouse con il seguente script:<br />
<br />
<br/>[[File:Palloncini3.png|center|Palloncini3.png]]<br />
<br />
<br/><span style="line-height: 1.6;">Questo script oltre a seguire il puntatore del mouse invia il messaggio "'''bang'''" quanto viene fatto click. Il messaggio verrà intercettato dai palloncini che controllano se sono stati colpiti e gestiscono il punteggio.</span><br />
<br />
Lo script del palloncino è strutturato in tre parti: una gestisce il cambio di costume (qui due per semplicità, ma se ne possono aggiungere a volontà), un'altra i messaggi "'''bang'''", l'ultima il volo verticale:<br />
<br />
<br/>[[File:Palloncini1.png|center|Palloncini1.png]]<br />
<br />
Lo script è realizzato per incorporare tutta la logica nello sprite in modo che la duplicazione dello sprite stesso possa permettere di inserire ulteriori palloncini con un copia e incollo senza modifiche al codice.<br />
<br />
E' possibile realizzare più tipi di palloncini, differenziandone le caratteristiche, per esempio con diverse velocità, che danno punteggi diversi.<br />
<br />
Inoltre può essere inserito un decremento del punteggio se il palloncino arriva in cima.<br />
<br />
Come ultima cosa va gestito il fine gioco, gestendo ad esempio un cronometro.<br />
[[Category:Scratch|P]]</div>
Leoncino
https://kata.coderdojo.it/wiki/index.php?title=Colora_il_box
Colora il box
2014-09-21T16:16:22Z
<p>Margherita: </p>
<hr />
<div>= Colora il box =<br />
<br />
Questo tutorial è composto di 3 tutorial che sviluppano lo stesso esercizio di programmazione (colorare un box quadrato) in tre modalità di livello (difficoltà e competenze) crescente:<br />
<br />
*Colora il box - livello base<br />
*Colora il box - livello intermedio<br />
*Colora il box - livello avanzato<br />
<br />
== Colora il box - livello base ==<br />
<br />
Questo semplice tutorial combina conoscenze basiche di HTML, CSS e Javascript.<br />
<br />
Il suo scopo è quello di colorare un quadrato inizialmente nero, scegliendo una combinazione dei tre colori base rosso, verde e blu (terna RGB: Red Green Blue) cioè scegliendo una terna RGB.<br />
<br />
La scelta del valore per il rosso, verde o blu viene fatto inserendo un valore a scelta tra 0 e 255 per ciascuno dei tre colori.<br />
<br />
Consiste nella creazione, in una pagina HTML, di un quadrato inizialmente nero insieme a tre box testuali in cui l'utente potrà inserire i tre valori scelti per la terna RGB.<br />
<br />
In particolare il codice HTML è il seguente;<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;">&lt;html&gt;<br/>&nbsp; &nbsp; &lt;body&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Rosso (0 - 255): &lt;input type="Text" id="rosso" value=0 &gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Verde (0 - 255): &lt;input type="Text" id="verde" value=0 &gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Blu (0 - 255): &lt;input type="Text" id="blu" value=0 &gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Codice esadecimale del colore risultante: &lt;label id='codice'&gt;#000000&lt;/label&gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div style="height:100px; width:100px; background-color:#000000; border:1" id="colore"&gt;&lt;/div&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&lt;/html&gt;<br/></div><br />
in cui si possono notare i tre elementi HTML &lt;input type="text"&gt; che conterranno i tre numeri (0-255) per i tre colori della terna RGB, cioè rosso, verde e blu e che inzialmente sono a 0 (value=0).&nbsp;<br />
<br />
Dopo questi tre campi è presente una etichetta (tag &lt;label&gt;) che riporterà il codice esadecimale del colore risultante dalla combinazione dei tre colori base e cioè il codice della terna RGB.<br />
<br />
Infine, è presente un tag &lt;div&gt; a cui sono state date le carattersitche di un quadrato nero grazie alle impostazione di stile: l'attributo style, infatti, ne specifica lo stile definendo un'altezza ed una base entrambe di 100px (height:100px; width:100px;), un colore di sfondo pari al nero (background-color:#000000;) ed un bordo sottile (border:1).<br />
<br />
Il codice così riportato disegna una pagina del tipo:<br />
<br />
[[File:Colore-mini.png|border|center|Colore-mini.png]]<br />
<br />
<br />
<br />
ma questa pagina html non è ancora in grado di far cambiare il colore al quadrato nero, perché manca il codice Javascript necessario a impostare la terna RGB (i tre valori tra 0 e 255) inserita dall'utente nei tre box testuali indicati con ''Rosso (0 - 255)'', ''Verde (0 - 255)'',&nbsp;''Blu (0 - 255)''.<br />
<br />
Il codice Javascript, riportato di seguito, contiene due funzioni:<br />
<br />
*''calcolaCodice()'': restituisce una stringa contenente il codice HTML del colore ottenuto dalla combinazione delle tre componenti RGB; infatti, trasforma le tre componenti scelte dall'utente (numeri decimali tra 0 e 255) in numeri esadecimali e li scrive in successione in una stringa aggiungendo all'inizio il carattere '#'. Si ottengono stringhe del tipo #000000 (nero), #FF0000 (rosso), #FFFFFF (bianco) etc<br />
*colora(id): usa la calcolaCodice() per calcolare il codice di colore HTML e per colorare il quadrato di tale colore, cambiando le impostazioni di stile del quadrato dell'attributo ''background-color''. Inoltre modifica l'etichetta &lt;label&gt; scrivendo il codice di colore risultante dalla combinazione RGB scelta.<br />
<br />
<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;"><br />
&nbsp; &nbsp; &nbsp; &nbsp; function calcolaCodice(){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;r=parseInt(document.getElementById('rosso').value);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;g=parseInt(document.getElementById('verde').value);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;b=parseInt(document.getElementById('blu').value);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return '#'+ ('0'+r.toString(16)).slice(-2)+('0'+g.toString(16)).slice(-2)+('0'+b.toString(16)).slice(-2);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function colora(id){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;c=calcolaCodice();<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;div=document.getElementById(id);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;div.style.backgroundColor=c;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById('codice').innerHTML=c;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
</div><br />
E quindi, di seguito, il codice della pagina completo<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;">&lt;html&gt;<br/>&nbsp; &nbsp; &lt;head&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;script language="javascript"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function calcolaCodice(){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;r=parseInt(document.getElementById('rosso').value);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;g=parseInt(document.getElementById('verde').value);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;b=parseInt(document.getElementById('blu').value);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return '#'+ ('0'+r.toString(16)).slice(-2)+('0'+g.toString(16)).slice(-2)+('0'+b.toString(16)).slice(-2);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function colora(id){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;c=calcolaCodice();<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;div=document.getElementById(id);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;div.style.backgroundColor=c;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById('codice').innerHTML=c;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/script&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;body&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Rosso (0 - 255): <input type="Text" id="rosso" value=0 onblur="colora('<span style="background-color: rgb(238, 238, 238);">quadrato</span>')">&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Verde (0 - 255): <input type="Text" id="verde" value=0 onblur="colora('<span style="background-color: rgb(238, 238, 238);">quadrato</span>')">&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Blu (0 - 255): <input type="Text" id="blu" value=0 onblur="colora('<span style="background-color: rgb(238, 238, 238);">quadrato</span>')">&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Codice esadecimale del colore risultante: &lt;label id='codice'&gt;#000000&lt;/label&gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div style="height:100px; width:100px; background-color:#000000; border:1" id="quadrato"&gt;&lt;/div&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&lt;/html&gt;<br/></div><br />
Notare la chiamata della funzione ''colora(id)'' nel codice HTML attraverso l'attributo ''onblur'' che rappresenta l'evento di perdita del 'fuoco' dell'oggetto in considerazione: in altre parole, tutte le volte che l'utente uscirà da una dei tre box testuali (che abbia o meno scritto un valore) verrà reimpostato il colore del quadrato secondo la scelta fatta. Notare anche che la funzione ''colora(id)'' è chiamata passando l'id del &lt;div&gt; che disegna il quadrato e cioè ''colora('<span style="background-color: rgb(238, 238, 238);">quadrato'</span>)''.<br />
<br />
== Colora il box - livello intermedio ==<br />
<br />
Questo tutorial combina conoscenze di HTML, CSS e Javascript. L'obiettivo è sempre quello di colorare un box quadrato scegliendo la terna RGB, ma la scelta può essere fatta (oltre che scrivendo nei box testuali il valore per rosso, verde e blu) &nbsp;anche usando dei bottoni che incrementano o decrementano il valore decimale. Questa versione dell'esercizio rispetto al livello base, quindi, si complica in quanto aumenta sia la presenza di oggetti HTML (bottoni) sia il codice Javascript &nbsp;che li gestisce.<br />
<br />
Il codice dell'esercizio completo è il seguente:<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;">&lt;html&gt;<br/>&nbsp; &nbsp; &lt;head&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;script language="javascript"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function calcolaCodice(){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;r=parseInt(document.getElementById('rosso').value);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;g=parseInt(document.getElementById('verde').value);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;b=parseInt(document.getElementById('blu').value);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return '#'+ ('0'+r.toString(16)).slice(-2)+('0'+g.toString(16)).slice(-2)+('0'+b.toString(16)).slice(-2);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function colora(id){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;c=calcolaCodice();<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;div=document.getElementById(id);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;div.style.backgroundColor=c;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById('codice').innerHTML=c;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function inizia(){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;r=document.getElementById('rosso').value='0';<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;g=document.getElementById('verde').value='0';<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;b=document.getElementById('blu').value='0';<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function varia(casella,v){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ct=document.getElementById(casella);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;x=parseInt(ct.value);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;x=x+v;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (x>255) x=255;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (x<0) x=0;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ct.value=x;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/script&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;body onload="inizia();colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="aumenta R" onclick="varia('rosso',1);colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="diminuisci R" onclick="varia('rosso',-1);colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Rosso (0 - 255): &lt;input type="Text" id="rosso" onblur="colora('quadrato')"&gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="aumenta G" onclick="varia('verde',1);colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="diminuisci G" onclick="varia('verde',-1);colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Verde (0 - 255): &lt;input type="Text" id="verde" onblur="colora('quadrato')"&gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="aumenta B" onclick="varia('blu',1);colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="diminuisci B" onclick="varia('blu',-1);colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Blu (0 - 255): &lt;input type="Text" id="blu" onblur="colora('quadrato')"&gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Codice esadecimale del colore risultante: &lt;label id='codice'&gt;&lt;/label&gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div style="height:100px; width:100px" id="quadrato"&gt;&lt;/div&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&lt;/html&gt;<br/></div><br />
e la pagina HTML risultante è&nbsp;<br />
<br />
[[File:Colore1-mini.png|border|center|Colore1-mini.png]]<br />
<br />
== Colora il box - livello avanzato ==<br />
<br />
Questo tutorial combina conoscenze di HTML, CSS e Javascript. L'obiettivo è sempre quello di colorare un box quadrato scegliendo la terna RGB, ma la scelta può essere fatta solo usando i bottoni che incrementano o decrementano il valore decimale e la scelta effettuata viene riportata in corrispondenti etichette. Questa versione dell'esercizio rispetto al livello intermedio, quindi, non complica di fatto il livello ma prevede le competenze acquisite nel livello intermedio per semplificare l'esercizio; infatti, cambiano alcuni oggetti HTML sia il codice Javascript che li gestisce, in particolare nel codice Javascript viene fatto uso di variabili globali.<br />
<br />
Il codice dell'esercizio completo è il seguente:<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;">&lt;html&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;head&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;script language="javascript"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;var r,g,b,c;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function calcolaCodice(){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return '#'+ ('0'+r.toString(16)).slice(-2)+('0'+g.toString(16)).slice(-2)+('0'+b.toString(16)).slice(-2);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function colora(id){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;c=calcolaCodice();<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;div=document.getElementById(id);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;div.style.backgroundColor=c;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;mostraRGB();<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function mostraRGB(){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById('rosso').innerHTML=r.toString()+' '+r.toString(16);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById('verde').innerHTML=g.toString()+' '+g.toString(16);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById('blu').innerHTML=b.toString()+' '+b.toString(16);<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById('codice').innerHTML=c;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function inizia(){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;r=0;g=0;b=0;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function varia(x,v){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;x=x+v;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (x>255) return 255;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (x<0) return 0;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return x;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/script&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;body onload="inizia();colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="aumenta R" onclick="r=varia(r,1);colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="diminuisci R" onclick="r=varia(r,-1);colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Rosso: &lt;label id='rosso'&gt;&lt;/label&gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="aumenta G" onclick="g=varia(g,1);colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="diminuisci G" onclick="g=varia(g,-1);colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Verde: &lt;label id='verde'&gt;&lt;/label&gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="aumenta B" onclick="b=varia(b,1);colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="diminuisci B" onclick="b=varia(b,-1);colora('quadrato');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Blu: &lt;label id='blu'&gt;&lt;/label&gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;label id='codice'&gt;&lt;/label&gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div style="height:100px; width:100px" id="quadrato"&gt;&lt;/div&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&lt;/html&gt;<br/></div><br />
e la pagina HTML risultante è&nbsp;<br />
<br />
[[File:Colore2-mini.png|border|center]]<br />
[[Category:Javascript|Category:Javascript]]</div>
Margherita
https://kata.coderdojo.it/wiki/index.php?title=Tutorial:_Labirinto
Tutorial: Labirinto
2014-09-07T13:46:10Z
<p>Leoncino: </p>
<hr />
<div>== Gioco LABIRINTO (mentor) ==<br />
<br />
Questo semplice programma permette di muovere uno sprite all'interno di un labirinto, animando lo sprite utilizzando più costumi e gestendo le collisioni sulle "pareti" del labirinto. Dimostra quindi in modo elementare come:<br />
<br />
*utilizzare tasti per muovere uno sprite<br />
*utilizzare costumi multipli sullo stesso sprite alternandoli durante il movimento<br />
*utilizzare la condizione "tocca il colore" per effettuare operazioni automatiche sul movimento<br />
<br />
Il gioco può essere [http://kata.coderdojo.it/archivio/LABIRINTO.sb scaricato] dall'archivio kata.<br />
<br />
=== Creazione dello Stage (sfondo) ===<br />
<br />
Come prima cosa occorre realizzare lo '''Stage''' da utilizzare come sfondo per il gioco. L'unico requisito importante è che i muri del labirinto siano realizzati con la penna di colore nero in modo da poter correttamente in fase di codifica la collisione con le pareti. Occorre anche realizzare i corridoi del labirinto con una larghezza appropriata in modo da permettere allo sprite, che realizzeremo successivamente, di muoversi agevolmente all'interno del labirinto.<br />
<br />
Per modificare lo sfondo, andare nell'area Stage, selezionare il tab "Sfondi" e selezionare "Modifica". Nella figura che segue è riportata la finestra Editor di immagini con un esempio di labirinto.<br />
<br />
[[File:Editor stage.png|File:Editor_stage.png]]<br />
<br />
=== Sprite: disegno dei costumi ===<br />
<br />
Come sprite useremo una palla costituita da due costumi che si alternano continuamente per creare un effetto animato elementare in stile Pac-Man. Creare lo sprite cliccando sull'icona "Disegna nuovo sprite":<br />
<br />
[[File:Crea nuovo sprite.png|File:Crea_nuovo_sprite.png]]<br />
<br />
Si aprirà la finestra dell'editor di immagini. Disegnare un semplice cerchio di un colore a piacere (purché non nero). Scegliere la dimensione in modo che lo sprite sia ben visibile ma che si possa muovere agevolmente all'interno del labirinto. Alla fine di questa operazione lo sprite deve apparire sopra lo stage per esempio come riportato nella seguente immagine:<br />
<br />
[[File:Scratch labirinto sprite costume 1.png|File:Scratch_labirinto_sprite_costume_1.png]]<br />
<br />
Per realizzare il secondo costume dello sprite operare come segue:<br />
<br />
*duplicare il primo costume realizzando cliccando sul pulsante "copia" accanto al costume:<br />
<br />
[[File:Scratch labirinto copia costume.png|File:Scratch_labirinto_copia_costume.png]]<br />
<br />
*cliccare sul pulsante "modifica" accanto al secondo costume. Cancellare alcuni pixel del corpo in modo da realizzare una "bocca". Alla fine dell'operazione i due costumi appariranno così:<br />
<br />
[[File:Scratch labirinto i due costumi.png|File:Scratch_labirinto_i_due_costumi.png]]<br />
<br />
<br />
<br />
=== Sprite: codice ===<br />
<br />
Il codice da associare allo sprite appena realizzato è costituito da tre gruppi di script:<br />
<br />
*Script per il posizionamento iniziale dello sprite e per gestire l'alternanza dei costumi<br />
*Script per gestire il movimento dello sprite utilizzando le frecce<br />
*Script per gestire le collisioni con le pareti del labirinto.<br />
<br />
L'insieme si tutto il codice da realizzare è riportato nell'immagine che segue:<br />
<br />
<br/>[[File:Scratch labirinto codice.png|File:Scratch_labirinto_codice.png]]<br />
<br />
<br />
<br />
=== Esercizi ===<br />
<br />
*Estendere l'algoritmo di movimento in modo da permettere anche gli spostamenti in diagonale (attenzione... c'è una soluzione semplice ma sbagliata e una corretta).<br />
[[Category:Scratch|L]]</div>
Fpiantini
https://kata.coderdojo.it/wiki/index.php?title=Movimento_con_il_mouse_Scratch
Movimento con il mouse Scratch
2014-08-29T16:58:57Z
<p>Fpiantini: </p>
<hr />
<div>= Movimento con il Mouse =<br />
<br />
<span style="line-height: 1.6">Muovere uno sprite utilizzando il mouse può essere fatto in vari modi.</span><br />
<br />
== Inseguimento del Mouse ==<br />
<br />
Si realizza con il blocco "punta verso...." per far puntare lo sprite verso il mouse, e con "fai ... passi" per muovere lo sprite, come nell'esempio seguente:<br/>[[File:Movimento mouse.png|File:Movimento mouse.png]]<br />
<br />
Questo script ha come effetto sgradevole che se il mouse si ferma lo sprite una volta raggiunto il puntatore "impazzisce", ovvero inizia a ribaltarsi all'infinito.<br />
<br />
Per evitare questo effetto si può modificare lo script introducendo il controllo che se lo sprite è troppo vicino al puntatore il movimento non viene fatto così come mostrato di seguito:<br/>[[File:Movimento mouse 2.png|File:Movimento mouse 2.png]]<br />
<br />
Si può aggiungere anche un po' di animazione facendo cambiare il costume allo sprite a ogni movimento:<br/>[[File:Movimento mouse 3.png|File:Movimento mouse 3.png]]<br />
<br />
Si può anche gestire un mirino per i giochi di sparo, realizzando uno sprite con un croce o simile e utilizzano il comando "raggiungi puntatore del mouse", lo script seguente invia anche un messaggio se si fa click con il mouse<br/>[[File:Puntatore mouse.png|File:Puntatore mouse.png]]<br />
[[Category:Scratch|M]]</div>
Leoncino
https://kata.coderdojo.it/wiki/index.php?title=Il_mio_Blog_HTML
Il mio Blog HTML
2014-08-29T16:54:50Z
<p>Margherita: il mio Blog html</p>
<hr />
<div>= Il mio Blog HTML =<br />
<br />
Questo tutorial descrive la creazione di un semplice blog con HTML e CSS.<br/>L'esercizio consiste nella creazione di quattro pagine HTML:<br />
<br />
*index.html, homepage del blog;<br />
*chisono.html, contenente una descrizione del proprietario del blog;<br />
*cosamipiace.html, contenente una descrizione delle preferenze del proprietario del blog;<br />
*cosafaro.html, contenente una descrizione dei progetti futuri del proprietario del blog.<br />
<br />
I quattro file sono quasi uguali: disegnano un riquadro centrale con un menu sovrastante&nbsp;su uno sfondo personalizzato e si distinguono solo per il contenuto del riquadro centrale.<br />
<br />
== passo 1: realizzazione della pagina homepage ==<br />
<br />
Il codice seguente è composto dalle sezioni di base della pagina html:<br/>&lt;head&gt;: contiene il titolo (tag &lt;title&gt;) della pagina e le impostazioni di stile comuni (tag &lt;style&gt;)<br/>&lt;body&gt;: contiene tre tabelle allineate in verticale che si riferiscono alle tre parti della pagina e cioè: menu (in alto), corpo (centrale) e piedipagina (in basso).<br />
<br />
'''index.html'''<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;"><span style="font-family:courier new,courier,monospace;">&lt;html&gt;<br/>&nbsp; &nbsp; &lt;head&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;title&gt;Il mio Blog&lt;/title&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;style&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;body{<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;font-family:Arial, Helvetica;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-image:url('personcina.png');<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.cellamenu{<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-color:#D4E6CA;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;height:50px;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;width:25%;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;text-align:center;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cursor:pointer;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.cellamenuselezionata{<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-color:#99FF66;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;height:50px;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;width:25%;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;text-align:center;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cursor:pointer;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/style&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;body onload="SelezionaPagina(document.getElementById('home'));"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;table id="menu" align="center" style="border:0;width:800px;"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="home" class="cellamenuselezionata"&gt;Home&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="chisono" class="cellamenu" &gt;&lt;a href="chisono.html"&gt;Chi Sono&lt;/a&gt;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="cosapiace" class="cellamenu"&gt;&lt;a href="cosamipiace.html"&gt;Cosa mi piace&lt;/a&gt;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="cosafaro" class="cellamenu" &gt;&lt;a href="cosafaro.html"&gt;Cosa farò da grande&lt;/a&gt;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/table&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;table id="corpo" align="center" style="border:1px solid #000000;width:800px;background-color:#D4E6CA;height:600px;"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;tr id="corpohome"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<div style="background-image:url('nuvola2.png');background-repeat:no-repeat;height:184px;margin-left:200px;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;margin-top:10px;width:300px;text-align:center;"><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;span style="position:relative;left:10px;top:80px;"&gt;Questa è la home page del blog di margherita&lt;/span&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/table&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;table id="piedipagina" align="center" style="border:0;width:800px;"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td style="text-align:center;border-top:1px solid red;width:100%;font-weight:bold;font-size:12px;background-color:#FFFFFF;"&gt;MDV Copyleft 2014&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/table&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&lt;/html&gt;</span><br/></div><br />
== passo 2: realizzazione delle altre tre pagine del blog ==<br />
<br />
Le altre tre pagine html si distiguono da questa solo per la modifica del contenuto della tabella con id="corpo". Di seguito i sorgenti di queste pagine.<br />
<br />
'''chisono.html'''<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;"><span style="font-family:courier new,courier,monospace;">&lt;html&gt;<br/>&nbsp; &nbsp; &lt;head&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;title&gt;Il mio Blog&lt;/title&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;style&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;body{<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;font-family:Arial, Helvetica;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-image:url('personcina.png');<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.cellamenu{<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-color:#D4E6CA;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;height:50px;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;width:25%;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;text-align:center;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cursor:pointer;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.cellamenuselezionata{<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-color:#99FF66;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;height:50px;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;width:25%;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;text-align:center;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cursor:pointer;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/style&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;body onload="SelezionaPagina(document.getElementById('home'));"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;table id="menu" align="center" style="border:0;width:800px;"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="home" class="cellamenu"&gt;&lt;a href="index.html"&gt;Home&lt;/a&gt;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="chisono" class="cellamenuselezionata" &gt;Chi Sono&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="cosapiace" class="cellamenu"&gt;&lt;a href="cosamipiace.html"&gt;Cosa mi piace&lt;/a&gt;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="cosafaro" class="cellamenu" &gt;&lt;a href="cosafaro.html"&gt;Cosa farò da grande&lt;/a&gt;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/table&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;table id="corpo" align="center" style="border:1px solid #000000;width:800px;background-color:#D4E6CA;height:600px;"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;tr id="corpochisono"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<div style="background-image:url('nuvola2.png');background-repeat:no-repeat;height:184px;width:300px;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;margin-left:10px;margin-top:10px;text-align:center;"><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;span style="position:relative;left:10px;top:80px;"&gt;Questa sono io&lt;/span&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<div style="background-image:url('nuvola2.png');background-repeat:no-repeat;height:184px;width:300px;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;margin-left:200px;margin-top:50px;text-align:center;"><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;span style="position:relative;left:10px;top:80px;"&gt;Questa è la mia foto&lt;/span&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/table&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;table id="piedipagina" align="center" style="border:0;width:800px;"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td style="text-align:center;border-top:1px solid red;width:100%;font-weight:bold;font-size:12px;background-color:#FFFFFF;"&gt;MDV Copyleft 2014&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/table&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&lt;/html&gt;</span><br/></div><br />
<br/>'''cosamipiace.html'''<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;"><span style="font-family:courier new,courier,monospace;">&lt;html&gt;<br/>&nbsp; &nbsp; &lt;head&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;title&gt;Il mio Blog&lt;/title&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;style&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;body{<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;font-family:Arial, Helvetica;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-image:url('personcina.png');<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.cellamenu{<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-color:#D4E6CA;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;height:50px;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;width:25%;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;text-align:center;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cursor:pointer;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.cellamenuselezionata{<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-color:#99FF66;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;height:50px;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;width:25%;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;text-align:center;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cursor:pointer;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&lt;/style&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;body onload="SelezionaPagina(document.getElementById('home'));"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;table id="menu" align="center" style="border:0;width:800px;"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="home" class="cellamenu"&gt;&lt;a href="index.html"&gt;Home&lt;/a&gt;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="chisono" class="cellamenu" &gt;&lt;a href="chisono.html"&gt;Chi Sono&lt;/a&gt;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="cosapiace" class="cellamenuselezionata"&gt;Cosa mi piace&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="cosafaro" class="cellamenu" &gt;&lt;a href="cosafaro.html"&gt;Cosa farò da grande&lt;/a&gt;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/table&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;table id="corpo" align="center" style="border:1px solid #000000;width:800px;background-color:#D4E6CA;height:600px;"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;tr id="corpocosapiace"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Queste sono le cose che mi piacciono:&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;ul&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;li&gt;leggere&lt;/li&gt;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;li&gt;programmare&lt;/li&gt;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;li&gt;mangiare&lt;/li&gt;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;li&gt;nuotare&lt;/li&gt;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/ul&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;e poi mi piace questo video:&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<iframe width="420" height="315" src="[http://www.youtube.com/embed/OXrU2ECBH-E?rel=0 http://www.youtube.com/embed/OXrU2ECBH-E?rel=0]" frameborder="0" allowfullscreen>&lt;/iframe&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/table&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;table id="piedipagina" align="center" style="border:0;width:800px;"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td style="text-align:center;border-top:1px solid red;width:100%;font-weight:bold;font-size:12px;background-color:#FFFFFF;"&gt;MDV Copyleft 2014&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/table&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&lt;/html&gt;</span><br/></div><br />
<br/>'''cosafaro.html'''<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;"><span style="font-family:courier new,courier,monospace;">&lt;html&gt;<br/>&nbsp; &nbsp; &lt;head&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;title&gt;Il mio Blog&lt;/title&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;style&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;body{<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;font-family:Arial, Helvetica;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-image:url('personcina.png');<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.cellamenu{<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-color:#D4E6CA;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;height:50px;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;width:25%;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;text-align:center;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cursor:pointer;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.cellamenuselezionata{<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-color:#99FF66;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;height:50px;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;width:25%;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;text-align:center;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cursor:pointer;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/style&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;body onload="SelezionaPagina(document.getElementById('home'));"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;table id="menu" align="center" style="border:0;width:800px;"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="home" class="cellamenu"&gt;&lt;a href="index.html"&gt;Home&lt;/a&gt;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="chisono" class="cellamenu" &gt;&lt;a href="chisono.html"&gt;Chi Sono&lt;/a&gt;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="cosapiace" class="cellamenu"&gt;&lt;a href="cosamipiace.html"&gt;Cosa mi piace&lt;/a&gt;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td id="cosafaro" class="cellamenuselezionata" &gt;Cosa farò da grande&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/table&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;table id="corpo" align="center" style="border:1px solid #000000;width:800px;background-color:#D4E6CA;height:600px;"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;tr id="corpocosafaro"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Da grande farò .....&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Ma io sono già grandeeeeeeeee&lt;/p&gt;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/table&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;table id="piedipagina" align="center" style="border:0;width:800px;"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;td style="text-align:center;border-top:1px solid red;width:100%;font-weight:bold;font-size:12px;background-color:#FFFFFF;"&gt;MDV Copyleft 2014&lt;/td&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;tr&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/table&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&lt;/html&gt;</span></div><br />
Di seguito un'immagine di come si presenta la homepage del blog.<br/>[[File:IlmioBlogmini.png|IlmioBlogmini.png]]<br />
[[Category:HTML|Category:HTML]]</div>
Margherita
https://kata.coderdojo.it/wiki/index.php?title=Gioco_a_bivi_PHP
Gioco a bivi PHP
2014-08-29T16:31:33Z
<p>Leoncino: </p>
<hr />
<div>= Gioco a bivi PHP =<br />
<br />
<span style="color: rgb(0, 0, 0); font-family: sans-serif; line-height: 19.5px;">Il gioco a bivi descritto nella sezione&nbsp;</span>[http://kata.coderdojo.it/wiki/index.php?title=Gioco_a_bivi_html html]<span style="color: rgb(0, 0, 0); font-family: sans-serif; line-height: 19.5px;">&nbsp;rivisto in PHP.</span><br />
<br />
E' necessario disporre di un server WEB con l'interprete PHP e una modalità di pubblicazione (FTP, cartella condivisa....) sul server.<br />
<br />
<span style="color: rgb(0, 0, 0); font-family: sans-serif; line-height: 19.5px;">Si parte dal gioco a bivi minimale, semplicemente rinominando i file da .html a .php, modificando i link interni in modo che tutto continui a funzionare. Pertanto i file index.html, entra.html e salta.html diventano index.php, entra.php, salta.php.</span><br />
<br />
<span style="color: rgb(0, 0, 0); font-family: sans-serif; line-height: 19.5px;">Facciamo notare ai ragazzi che non è cambiato sostanzialmente nulla rispetto a prima.</span><br />
<br />
<font color="#000000" face="sans-serif"><span style="line-height: 19.5px;">Il passo successivo è il seguente codice php:</span></font><br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;"><span style="font-family:courier new,courier,monospace;"><?php<br/><span style="background-color:#FFFF00;">$v_scelta=$_GET["scelta"];</span><br/><span style="background-color:#FFFF00;">switch ($v_scelta){</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;case "entra":</span><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;$stanza='<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;html&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;body&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Sei dentro al castello&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Complimenti&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;img src="sala.jpg" /&gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;a href ="index.php"&gt;Torna Fuori&lt;/a&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/html&gt;';<br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;break;</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;case "salta":</span><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;$stanza='<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;html&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;body&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Sei stato un ottimo pasto per il coccodrillo, che ti ringrazia con affetto&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;img src="coccodrillo.jpg" /&gt;&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;a href ="index.php"&gt;Ricomincia&lt;/a&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/html&gt;';<br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;break;</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;default:</span><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;$stanza='<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;html&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;body&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Sei davanti a un castello circondato da un fossato pieno di coccodrilli.&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Puoi &lt;i&gt;entrare&lt;/i&gt; nel castello o &lt;i&gt;saltare&lt;/i&gt; nel fossato&lt;br/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;img src="castello.jpg" /&gt;&lt;/p&gt;<br/>&nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="background-color:#FFFF00;">&nbsp;&lt;a href ="index.php?scelta=entra"&gt;Entra&lt;/a&gt; o &lt;a href="index.php?scelta=salta"&gt;Salta&lt;/a&gt;</span><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/html&gt;';<br/>}<br/><span style="background-color:#FFFF00;">echo $stanza;</span><br/>?></span><br/></div><br />
In pratica si legge il parametro passato in GET, si usa un costrutto '''switch''' per selezionare la destinazione, e si valorizza la variabile $stanza con il codice html che rappresenta la destinazione.<br />
<br />
Va fatto notare come si definesce un parametro in GET.[[Category:PHP]]</div>
Leoncino
https://kata.coderdojo.it/wiki/index.php?title=PHP
PHP
2014-08-29T16:19:36Z
<p>Leoncino: PHP</p>
<hr />
<div>PHP (acronimo ricorsivo:&nbsp;PHP Hypertext Processor) è un linguaggio di programmazione molto usato per la realizzazione di applicazioni WEB[[Category:PHP]]</div>
Leoncino
https://kata.coderdojo.it/wiki/index.php?title=Gioco_a_bivi_javascript
Gioco a bivi javascript
2014-08-29T15:41:44Z
<p>Leoncino: </p>
<hr />
<div>= Gioco a bivi JAVASCRIPT =<br />
<br />
Il gioco a bivi descritto nella sezione [http://kata.coderdojo.it/wiki/index.php?title=Gioco_a_bivi_html html]&nbsp;rivisto con il Javascript. <br />
<br />
In pratica non si usano link a pagine diverse per passare da stanza a stanza, bensì si carica una pagina che contiene sia la parte grafica html che la parte di logica in javascript.<br />
<br />
E' utile articolare in passi l'esercizio fornendo il seguente codice html:<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;"><span style="font-family:courier new,courier,monospace;">&lt;html&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;title&gt;Gioco dei bivi col JavaScript&lt;/title&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;body&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h1&gt;Gioco dei bivi col JavaScript&lt;/h1&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="inizio"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h2&gt;Davanti al ponte levatoio&lt;/h2&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Ti trovi davanti a un castello che si dice contenga un prezioso tesoro.&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Sembra un luogo molto pericoloso, ma il ponte levatoio è abbassato. Potrebbe essere una trappola?&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Cosa preferisci, entrare dalla porta principale o attraversare il fossato a nuoto?&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="mi getto nel fossato pieno d'acqua"/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="entro dalla porta principale" /&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="fossato"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h2&gt;Il fossato intorno al Castello&lt;/h2&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Ehm...&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;C’erano i coccodrilli...&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Che brutta fine! Mi dispiace.&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="ricomincia" /&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="salone"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h2&gt;Il Salone del Castello&lt;/h2&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Sei entrato nel castello.&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;C’è un grande salone, arredato con fasto. Saccheggi completamente il castello e diventi ricco!&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Complimenti......&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" name="ricomincia" value="ricomincia" /&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&lt;/html&gt;</span></div><br />
Questo codice, se visualizzato nel browser, mostra &nbsp;i tre ambienti di gioco&nbsp;uno di seguito all'altro.<br />
<br />
Il passo successivo utilizza lo stile <span style="font-family:courier new,courier,monospace;">display:none</span> per nascondere i tre &lt;div&gt; degli ambienti di gioco, il codice diventa:<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;"><span style="font-family:courier new,courier,monospace;">&lt;html&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;title&gt;Gioco dei bivi col JavaScript&lt;/title&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;body&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h1&gt;Gioco dei bivi col JavaScript&lt;/h1&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<div id="inizio" <span style="background-color:#FFFF00;">style="display:none"</span>><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h2&gt;Davanti al ponte levatoio&lt;/h2&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Ti trovi davanti a un castello che si dice contenga un prezioso tesoro.&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Sembra un luogo molto pericoloso, ma il ponte levatoio è abbassato. Potrebbe essere una trappola?&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Cosa preferisci, entrare dalla porta principale o attraversare il fossato a nuoto?&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="mi getto nel fossato pieno d'acqua"/&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="entro dalla porta principale" /&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<div id="fossato" <span style="background-color:#FFFF00;">style="display:none"</span>><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h2&gt;Il fossato intorno al Castello&lt;/h2&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Ehm...&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;C’erano i coccodrilli...&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Che brutta fine! Mi dispiace.&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" value="ricomincia" /&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<div id="salone" <span style="background-color:#FFFF00;">style="display:none"</span>><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h2&gt;Il Salone del Castello&lt;/h2&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Sei entrato nel castello.&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;C’è un grande salone, arredato con fasto. Saccheggi completamente il castello e diventi ricco!&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Complimenti......&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" name="ricomincia" value="ricomincia" /&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&lt;/html&gt;</span></div><br />
A questo punto si inserisce la logica (function mostraDiv agganciata all'evento onclick dei button) che fa apparire e scomparire i &lt;div&gt; dei vari ambienti.<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;"><span style="font-family:courier new,courier,monospace;">&lt;html&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;title&gt;Gioco dei bivi col JavaScript&lt;/title&gt;<br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;script&gt;</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function mostraDiv(situazione){</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById('inizio').style.display="none";</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById('fossato').style.display="none";</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById('salone').style.display="none";</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById(situazione).style.display="block";</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}&nbsp;&nbsp; &nbsp;</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/script&gt;</span><br/>&nbsp;&nbsp; &nbsp;&lt;/head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;body onload="mostraDiv('inizio');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h1&gt;Gioco dei bivi col JavaScript&lt;/h1&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="inizio" style="display:none"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h2&gt;Davanti al ponte levatoio&lt;/h2&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Ti trovi davanti a un castello che si dice contenga un prezioso tesoro.&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Sembra un luogo molto pericoloso, ma il ponte levatoio è abbassato. Potrebbe essere una trappola?&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Cosa preferisci, entrare dalla porta principale o attraversare il fossato a nuoto?&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<input type="button" value="mi getto nel fossato pieno d'acqua" <span style="background-color:#FFFF00;">onclick="mostraDiv('fossato');"</span> /><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<input type="button" value="entro dalla porta principale" <span style="background-color:#FFFF00;">onclick="mostraDiv('salone');"</span> /><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="fossato" style="display:none"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h2&gt;Il fossato intorno al Castello&lt;/h2&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Ehm...&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;C’erano i coccodrilli...&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Che brutta fine! Mi dispiace.&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<input type="button" value="ricomincia" <span style="background-color:#FFFF00;">onclick="mostraDiv('inizio');"</span> /><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="salone" style="display:none"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h2&gt;Il Salone del Castello&lt;/h2&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Sei entrato nel castello.&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;C’è un grande salone, arredato con fasto. Saccheggi completamente il castello e diventi ricco!&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Complimenti......&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<input type="button" name="ricomincia" value="ricomincia" <span style="background-color:#FFFF00;">onclick="mostraDiv('inizio');"</span> /><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&lt;/html&gt;</span><br/></div><br />
L'ultimo passo è inserire qualche abbellimento tramite CSS:<br />
<div style="background:#eee;border:1px solid #ccc;padding:5px 10px;"><span style="font-family:courier new,courier,monospace;">&lt;html&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;head&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<span style="background-color:#FFFF00;">&lt;style&gt;</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;h1{</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;text-align: center;</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;text-decoration: underline;}</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.situazione{</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;display&nbsp;&nbsp; &nbsp;: none;</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;margin: 5% auto;</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;width: 90%;}</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.messaggio{</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-color: yellow;</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;color: blue;}</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.sconfitta{</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;background-color: black;</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;color: white;</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;font-size: larger;</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;text-align: center;}</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.centrato{</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;text-align: center;}</span><br/><span style="background-color:#FFFF00;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/style&gt;</span><br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;script&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;function mostraDiv(situazione){<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById('inizio').style.display="none";<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById('fossato').style.display="none";<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById('salone').style.display="none";<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;document.getElementById(situazione).style.display="block";<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/script&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;/head&gt;<br/>&nbsp;&nbsp; &nbsp;&lt;body onload="mostraDiv('inizio');"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h1&gt;Gioco dei bivi&lt;/h1&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="inizio" class="situazione"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h2&gt;Davanti al ponte levatoio&lt;/h2&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Ti trovi davanti a un castello che si dice contenga un prezioso tesoro.&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Sembra un luogo molto pericoloso, ma il ponte levatoio è abbassato. Potrebbe essere una trappola?&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<p <span style="background-color:#FFFF00;">class="messaggio"</span>>Cosa preferisci, entrare dalla porta principale o attraversare il fossato a nuoto?&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" name="in_fossato" value="mi getto nel fossato pieno d'acqua" onclick="mostraDiv('fossato');" /&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" name="alla_porta" value="entro dalla porta principale" onclick="mostraDiv('salone');" /&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="fossato" class="situazione"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h2&gt;Il fossato intorno al Castello&lt;/h2&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Ehm...&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;C’erano i coccodrilli...&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<p <span style="background-color:#FFFF00;">class="sconfitta"</span>>Che brutta fine! Mi dispiace.&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" name="ricomincia" value="ricomincia" onclick="mostraDiv('inizio');" /&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="salone" class="situazione"&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;h2&gt;Il Salone del Castello&lt;/h2&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;Sei entrato nel castello.&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;p&gt;C’è un grande salone, arredato con fasto. Saccheggi completamente il castello e diventi ricco!&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<p <span style="background-color:#FFFF00;">class="messaggio"</span>>Complimenti......&lt;/p&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;input type="button" name="ricomincia" value="ricomincia" onclick="mostraDiv('inizio');" /&gt;<br/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;&nbsp;&nbsp; &nbsp;<br/>&nbsp;&nbsp; &nbsp;&lt;/body&gt;<br/>&lt;/html&gt;</span><br/></div>[[Category:Javascript|Category:Javascript]]</div>
Leoncino
https://kata.coderdojo.it/wiki/index.php?title=Javascript
Javascript
2014-08-29T15:31:42Z
<p>Leoncino: Creata pagina con "JavaScript è un linguaggio utilizzato nelle pagine web per aggiungere componenti dinamici.Category:javascript"</p>
<hr />
<div>JavaScript è un linguaggio utilizzato nelle pagine web per aggiungere componenti dinamici.[[Category:javascript]]</div>
Leoncino
https://kata.coderdojo.it/wiki/index.php?title=Gioco_a_bivi_html
Gioco a bivi html
2014-08-29T15:10:17Z
<p>Leoncino: </p>
<hr />
<div>= Gioco a bivi: Avventura nel castello =<br />
<br />
Si trae ispirazione dal gioco in 5 righe di html, diffuso dal Dojo di Galway. Si tratta di costruire un percorso a scelte multiple tramite link a diverse pagine html. Inizialmente si dà priorità alla logica del gioco usando pochi tag html e nessun elemento di stile, per inserire successivamente ulteriori elementi html e di stile che permetteranno di abbellire le pagine.&nbsp;<br />
<br />
Il sorgente del gioco, con vari tipi di abbellimento grafico è scaricabile [http://kata.coderdojo.it/archivio/bivi.zip qui]<br />
<br />
== Passo 1: Logica del gioco ==<br />
<br />
È il momento di creare una cartella per contenere i vari file che saranno necessari, dopodiché si parte realizzando la pagina index.html con il seguente codice:<br />
<br />
<span style="line-height: 1.6;">index.html:</span><br />
<pre style="border: 1px solid rgb(204, 204, 204); padding: 5px 10px; background: rgb(238, 238, 238);"><html>&nbsp;<br />
<body>&nbsp;<br />
<p>Sei davanti a un castello circondato da un fossato pieno di coccodrilli.<br/>&nbsp;<br />
Puoi <i>entrare</i> nel castello o <i>saltare</i> nel fossato<br/>&nbsp;<br />
<img src="castello.jpg" /></p>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<a href ="entra.html">Entra</a> o <a href="salta.html"> Salta </a>&nbsp;<br />
</body>&nbsp;<br />
</html>&nbsp;<br />
</pre><br />
Questa pagina dà due scelte, di passare alla pagina entra.html, o alla pagina salta.html che sono le seguenti:<br />
<br />
<span style="line-height: 1.6;">entra.html:</span><br />
<pre style="border: 1px solid rgb(204, 204, 204); padding: 5px 10px; background: rgb(238, 238, 238);"><html>&nbsp;<br />
<body>&nbsp;<br />
<p>Sei dentro al castello<br/>&nbsp;<br />
Complimenti</p>&nbsp;<br />
<img src="sala.jpg" /><br/>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<a href ="index.html">Torna Fuori</a>&nbsp;<br />
</body>&nbsp;<br />
</html>&nbsp;<br />
</pre><br />
<span style="line-height: 1.6;">salta.html:</span><br />
<pre style="border: 1px solid rgb(204, 204, 204); padding: 5px 10px; background: rgb(238, 238, 238);"><html>&nbsp;<br />
<body>&nbsp;<br />
<p>Sei stato un ottimo pasto per il coccodrillo, che ti ringrazia con affetto</p>&nbsp;<br />
<img src="coccodrillo.jpg" /><br/>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<a href ="index.html">Ricomincia</a>&nbsp;<br />
</body>&nbsp;<br />
</html>&nbsp;<br />
</pre><br />
<span style="line-height: 1.6;">Le pagine fanno riferimento a immagini che sono nella stessa cartella dei file html, e devono ovviamente essere già state predisposte.</span><br />
<br />
A questo punto i ragazzi possono estendere o complicare la logica aumentando il numero di scelte, e il numero di livelli.<br />
<br />
== Passo 2: abbellimento grafico ==<br />
<br />
Si inseriscono sia nuovi tag html, che elementi di stile, in particolare:<br />
<br />
'''&lt;head&gt;, &lt;title&gt;, &lt;style&gt;, &lt;h1&gt;''' come tag;<br />
<br />
diversi elementi di stile per gestire colore dei font, colore di sfondo e caratteristiche grafiche dei link.<br />
<br />
<span style="line-height: 1.6;">index.html diventa:</span><br />
<pre style="border: 1px solid rgb(204, 204, 204); padding: 5px 10px; background: rgb(238, 238, 238);"><html>&nbsp;<br />
<head>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<title>Avventura nel castello</title>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<style>&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;p { &nbsp;&nbsp; &nbsp;color: white;&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;font-size: 16px;&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;a {&nbsp;&nbsp; &nbsp;text-decoration: none;&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;color: blue;&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}&nbsp;<br />
&nbsp;&nbsp; &nbsp;</style>&nbsp;<br />
</head>&nbsp;<br />
<body style="background-color:black">&nbsp;<br />
&nbsp;&nbsp; &nbsp;<h1 style="color:lightblue">Avventura nel castello</h1>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<p>Sei davanti a un castello circondato da un fossato pieno di coccodrilli.<br/>&nbsp;<br />
Puoi <i>entrare</i> nel castello o <i>saltare</i> nel fossato<br/>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<img src="castello.jpg" /></p>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<p><a href ="entra.html">Entra</a> o <a href="salta.html">Salta</a></p>&nbsp;<br />
</body>&nbsp;<br />
</html><br />
</pre><br />
<span style="line-height: 1.6;">Su questa falsariga si modificano entra.html e salta.html, facendo usare le funzioni di copia e incolla. Si mette in evidenza che è sufficiente copiare e incollare il tag '''&lt;style&gt;''' per replicare le caratteristiche grafiche della pagina index.html sulle altre</span><br />
<br />
<span style="line-height: 1.6;">entra.html:</span><br />
<pre style="border: 1px solid rgb(204, 204, 204); padding: 5px 10px; background: rgb(238, 238, 238);"><html>&nbsp;<br />
<head>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<title>Avventura nel castello - Hai vinto!</title>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<style>&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;p { color: white;&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;font-size: 16px;&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;a {&nbsp;&nbsp; &nbsp;text-decoration: none;&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;color: blue;&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}&nbsp;<br />
&nbsp;&nbsp; &nbsp;</style>&nbsp;<br />
</head>&nbsp;<br />
<body style="background-color:black">&nbsp;<br />
&nbsp;&nbsp; &nbsp;<h1 style="color:green">Avventura nel castello - Hai vinto!</h1>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<p>Sei dentro al castello<br/>&nbsp;<br />
Complimenti</p>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<img src="sala.jpg" /><br/>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<a href ="index.html">Torna Fuori</a>&nbsp;<br />
</body>&nbsp;<br />
</html>&nbsp;<br />
</pre><br />
<span style="line-height: 1.6;">salta.html:</span><br />
<pre style="border: 1px solid rgb(204, 204, 204); padding: 5px 10px; background: rgb(238, 238, 238);"><html>&nbsp;<br />
<head>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<title>Avventura nel castello - Hai perso!</title>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<style>&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;p { color: white;&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;font-size: 16px;&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;a {&nbsp;&nbsp; &nbsp;text-decoration: none;&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;color: blue;&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}&nbsp;<br />
&nbsp;&nbsp; &nbsp;</style>&nbsp;<br />
</head>&nbsp;<br />
<body style="background-color:red">&nbsp;<br />
&nbsp;&nbsp; &nbsp;<h1 style="color:black">Avventura nel castello - Hai perso!</h1>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<p>Sei stato un ottimo pasto per il coccodrillo, che ti ringrazia con affetto</p>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<img src="coccodrillo.jpg" /><br/>&nbsp;<br />
&nbsp;&nbsp; &nbsp;<a href ="index.html">Ricomincia</a>&nbsp;<br />
</body>&nbsp;<br />
</html></pre><br />
<span style="line-height: 1.6;">Si vede come le impostazioni generali di stile possano essere definite nella sezione </span>'''&lt;head&gt;'''''<b><span style="line-height: 1.6;">,</span></b>''<span style="line-height: 1.6;">inserendole una sola volta, mentre le impostazioni specifiche di un tag vadano inserite nel tag stesso, come nei tag&nbsp;</span>'''&lt;h1&gt;'''&nbsp;e&nbsp;'''&lt;body&gt;'''<span style="line-height: 1.6;">.</span><br />
[[Category:HTML|Category:HTML]]</div>
Leoncino
https://kata.coderdojo.it/wiki/index.php?title=Html
Html
2014-08-29T14:53:54Z
<p>Leoncino: </p>
<hr />
<div>HTML sta per HyperText Makup Language ed è il linguaggio con cui vengono scritte le pagine web<br />
<br />
[[Category:HTML]]</div>
Leoncino
https://kata.coderdojo.it/wiki/index.php?title=Movimento_con_i_tasti
Movimento con i tasti
2014-08-24T15:44:12Z
<p>Leoncino: Movimento con il mouse Scratch</p>
<hr />
<div>= Movimento con i tasti Scratch =<br />
<br />
== Movimento "classico" ==<br />
<br />
Per spostare uno sprite nelle 4 direzioni usando le frecce o altri tasti (es. “a s d w”) e ruotandolo&nbsp;nella direzione del moto, ci si aggancia all'evento '''“Quando si preme il tasto.....”''' come si vede nella seguente immagine:<br/>[[File:Movimenti1.png|File:Movimenti1.png]]<br/>Va gestito ogni tasto di movimento in maniera separata.&nbsp;<span style="line-height: 1.6;">In questo caso il comando '''“punta in&nbsp;direzione....” '''serve a direzionare lo sprite nella direzione del moto. Il numero di pixel di&nbsp;</span><span style="line-height: 1.6;">spostamento (3 nell'esempio) può essere variato per muovere più o meno velocemente lo sprite.</span><br />
<br />
Per ottenere un moto continuo è necessario tenere premuto il tasto della direzione del moto. Questo&nbsp;tipo di movimento si usa per muovere sprite lungo percorsi o labirinti.<br />
<br />
== <span style="line-height: 1.6;">Moto continuo&nbsp;</span> ==<br />
<br />
[[File:Movimenti2.png|File:Movimenti2.png]]<br/>Se si vuole un moto continuo, comandando soltanto la direzione di moto attraverso i tasti, è&nbsp;necessario utilizzare una variabile che conservi il tasto che di volta in volta viene premuto. Si può&nbsp;dunque produrre uno script come il seguente:<br/><br/>In questo caso si fa uso della variabile privata dello sprite “direzione” che viene impostata ogni volta che si preme un tasto,&nbsp;di un ciclo infinito (“per sempre”) in cui facciamo spostare lo sprite nella direzione definita dal&nbsp;tasto.<br />
[[Category:Scratch|M]]</div>
Leoncino
https://kata.coderdojo.it/wiki/index.php?title=Tutorial:_Tron
Tutorial: Tron
2014-08-24T15:29:06Z
<p>Leoncino: </p>
<hr />
<div>== Gioco TRON (mentor) ==<br />
<br />
Tron è un vecchio videogioco che prende spunto da un film di fantascienza del 1982, in cui delle motociclette si muovono lasciando scie che non devono incrociarsi. Per riprodurre un gioco simile, è necessario usare due sprite (uno per giocatore) che lascino una scia colorata, e gestire le collisioni degli sprite con le scie.<br />
<br />
Il gioco può essere [http://kata.coderdojo.it/archivio/tron1.sb scaricato] dall'archivio kata.<br />
<br />
Il movimento viene gestito solo per quanto riguarda la direzione, per cui la pressione di un tasto di movimento provoca la rotazione dello sprite, mentre la velocità dello sprite è sempre la stessa. Per questo movimento si può fare riferimento all'articolo "[[Movimento con i tasti|Movimento con i tasti]]".<br />
<br />
Il primo passo che va concluso prima della pausa è la creazione dello sprite e l'impostazione del movimento.<br />
<br />
La scia viene tracciata utilizzando il comando “penna giù” che disegna una linea di un colore predefinito lungo il percorso dello sprite. Nell'esempio le scie vengono disegnate con il colore rosso.<br />
<br />
La gestione delle collisioni con le scie viene fatta tramite il sensore “il colore … sta toccando il colore ….”.<br />
<br />
Gli sprite vanno disegnati con una forma affusolata e con una punta colorata che serve appunto a determinare la collisione con le scie. Gli sprite inoltre non possono toccare i bordi del campo di gioco. Nell'esempio gli sprite sono realizzati con forme triangolari nera e gialla ambedue con la punta di colore verde.<br/>[[File:Tron sprite1.png|File:Tron sprite1.png]]<br/>Lo script riportato è per lo sprite di colore nero, va duplicato per quello di colore giallo modificandolo opportunamente.<br />
<br />
La gestione della fine gioco è demandata allo sfondo con il seguente script<br/>[[File:Tron stage.png|File:Tron stage.png]]<br/>In pratica quando uno sprite va in collisione con una scia o con il bordo invia un messaggio che viene intercettato dallo sfondo che mostrerà un messaggio del tipo “Ha vinto il giallo” o “Ha vinto il nero” oltre al punteggio accumulato dai due giocatori.<br />
<br />
[[Category:Scratch]]</div>
Leoncino
https://kata.coderdojo.it/wiki/index.php?title=Scratch
Scratch
2014-08-24T14:18:48Z
<p>Leoncino: Scratch</p>
<hr />
<div>Scratch è un ambiente di programmazione visuale creato per avvicinare i bambini alla programmazione<br />
[[Category:Scratch]]</div>
Leoncino
https://kata.coderdojo.it/wiki/index.php?title=Pagina_principale
Pagina principale
2014-08-24T13:05:22Z
<p>Fpiantini: </p>
<hr />
<div>'''Benvenuti nel WIKI del CoderDojo di Firenze'''<br/><br/>In questo WIKI raccogliamo tutorial, articoli e linee guida da seguire durante i nostri incontri.<br/>Tutti i nostri mentor sono chiamati a collaborare al WIKI e possono farlo iscrivendosi liberamente.<br/><br/>La scrittura di un tutorial deve attenersi alle seguenti linee guida:<br/>- Avere una versione per i mentor<br/>- Avere una versione per i ragazzi (eventualmente tratta da quella per mentor)<br/>- Essere sviluppata per passi, con almeno un obiettivo intermedio da raggiungere entro la metà dell'incontro (prima della pausa).<br/>- Essere facilmente stampabile<br/>- Appartenere ad una categoria fra quelle disponibili<br />
<br />
Il contenuto di questo wiki è disponibile secondo la licenza [http://creativecommons.org/licenses/by-nc-sa/3.0/ Creative Commons, attribuzione non commerciale]<br />
<br />
Potete cominciare la vostra navigazione da qui:<br />
<br />
*[[:Category:Scratch|Scratch]]<br />
*[[:Category:HTML|HTML]]<br />
*[[:Category:Javascript|JavaScript]]<br />
*[[:Category:PHP|PHP]]<br />
*[[:Category:C++|C++]]<br />
*[[:Category:AppInventor|AppInventor]]<br />
*[[:Category:Python|Python]]<br />
*[[:Category:Minecraft|Minecraft]]<br />
<br />
[[Category:Principale|Category:Principale]]</div>
Leoncino