Delegati (Guida per programmatori C++)
Il C++ non è complicato, è vasto. L’idea che un linguaggio vada imparato e usato per intero è tipica dei linguaggi di nuova generazione come il Java, ma non è assolutamente una cosa necessaria in genere. Il cpp parte dal principio che se è possibile fare una cosa il linguaggio deve permetterlo, se poi i quattro tipi di cast o l’ereditarietà multipla fanno orrore o paura… non usateli!
Resta il fatto che siano utili e comodi per fare workaround, e i workaround servono ( nel mondo reale almeno) e anche fare cose orribili come modificare le variabili dichiarate costanti può tornare utile.
Oggi, in particolare, parleremo dei Delegati.
Con il termine Delegate (Delegati) si indica un particolare tipo di dato che è in grado di “contenere” un metodo, ossia una procedura o una funzione. In realtà, il verbo “contenere” non è propriamente esatto, ma serve per rendere più incisiva la definizione. Come esistono tipi di dato per gli interi, i decimali, le date, le stringhe, gli oggetti, ne esistono anche per i metodi, anche se può sembrare un po’ strano. Per chi avesse studiato altri linguaggi prima di approcciarsi al VB.NET, possiamo assimilare i Delegate ai tipi procedurali del Pascal o ai puntatori a funzione del C. Ad ogni modo, i delegate sono leggermente diversi da questi ultimi e presentano alcuni tratti particolari:
- Un delegate non può contenere qualsiasi metodo, ma che dei limiti. Infatti, è in grado di contenere solo metodi con la stessa signature specificata nella definizione del tipo. Fra breve vedremo in cosa consiste questo punto;
- Un delegate può contenere sia metodi di istanza sia metodi statici, a patto che questi rispettino la regole di cui al punto sopra;
- Un delegate è un tipo reference, quindi si comporta come un comunissimo oggetto, seguendo quelle regole che mi sembra di aver già ripetuto fino alla noia;
- Un oggetto di tipo delegate è un oggetto immutabile, ossia, una volta creato, non può essere modificato. Per questo motivo, non espone alcuna proprietà (tranne due in sola lettura). D’altra parte, questo comportamento era prevedibile fin dalla definizione: infatti, se un delegate contiene un riferimento ad un metodo – e quindi un metodo già esistente e magari definito in un’altra parte del codice – come si farebbe a modificarlo? Non si potrebbe modificare la signature perché questo andrebbe in conflitto con la sua natura, e non si potrebbe modificarne il corpo perché si tratta di codice già scritto (ricordate che gli oggetti esistono solo a run-time, perché vengono creati solo dopo l’avvio del programma, e tutto il codice è già stato compilato e trasformato in linguaggio macchina intermedio);
- Un delegate è un tipo safe, ossia non può mai contenere riferimenti ad indirizzi di memoria che non indichino espressamente un metodo (al contrario dei pericolosi puntatori del C).
Questa introduzione potrebbe apparire un po’ troppo teorica e fumosa, ma serve per comprendere il comportamento dei delegate.
Un esempio pratico dei delegati
I delegati sono particolarmente utili per risparmiare spazio nel codice. Tramite i delegate, infatti, possiamo usare lo stesso metodo per eseguire più compiti differenti. Dato che una variabile delegate contiene un riferimento ad un metodo qualsiasi, semplicemente cambiando questo riferimento possiamo eseguire codici diversi richiamando la stessa variabile. E’ come se potessimo “innestare” del codice sempre diverso su un substrato costante. Ecco un esempio piccolo, ma significativo:
Module Module2 'Nome del file da cercare Dim File As String 'Questo delegate referenzia una funzione che accetta un 'parametro stringa e restituisce un valore booleano Delegate Function IsMyFile(ByVal FileName As String) As Boolean 'Funzione 1, stampa il contenuto del file a schermo Function PrintFile(ByVal FileName As String) As Boolean 'Io.Path.GetFileName(F) restituisce solo il nome del 'singolo file F, togliendo il percorso delle cartelle If IO.Path.GetFileName(FileName) = File Then 'IO.File.ReadAllText(F) restituisce il testo contenuto 'nel file F in una sola operazione Console.WriteLine(IO.File.ReadAllText(FileName)) Return True End If Return False End Function 'Funzione 2, copia il file sul desktop Function CopyFile(ByVal FileName As String) As Boolean If IO.Path.GetFileName(FileName) = File Then 'IO.File.Copy(S, D) copia il file S nel file D: 'se D non esiste viene creato, se esiste viene 'sovrascritto IO.File.Copy(FileName, _ My.Computer.FileSystem.SpecialDirectories.Desktop & _ "" & File) Return True End If Return False End Function 'Procedura ricorsiva che cerca il file Function SearchFile(ByVal Dir As String, ByVal IsOK As IsMyFile) _ As Boolean 'Ottiene tutte le sottodirectory Dim Dirs() As String = IO.Directory.GetDirectories(Dir) 'Ottiene tutti i files Dim Files() As String = IO.Directory.GetFiles(Dir) 'Analizza ogni file per vedere se è quello cercato For Each F As String In Files 'È il file cercato, basta cercare If IsOK(F) Then 'Termina la funzione e restituisce Vero, cosicché 'anche nel for sulle cartelle si termini 'la ricerca Return True End If Next 'Analizza tutte le sottocartelle For Each D As String In Dirs If SearchFile(D, IsOK) Then 'Termina ricorsivamente la ricerca Return True End If Next End Function Sub Main() Dim Dir As String Console.WriteLine("Inserire il nome file da cercare:") File = Console.ReadLine Console.WriteLine("Inserire la cartella in cui cercare:") Dir = Console.ReadLine 'Cerca il file e lo scrive a schermo SearchFile(Dir, AddressOf PrintFile) 'Cerca il file e lo copia sul desktop SearchFile(Dir, AddressOf CopyFile) Console.ReadKey() End Sub End Module
Nel sorgente si vede che si usano pochissime righe per far compiere due operazioni molto differenti alla stessa procedura. In altre condizioni, un aspirante programmatore che non conoscesse i delegate avrebbe scritto due procedure intere, sprecando più spazio, e condannandosi, inoltre, a riscrivere la stessa cosa per ogni futura variante.
Le callback
Un altro uso classico dei delegate
(Delegati) è nelle callback
, chiamate quando si fa qualcosa sull’interfaccia utente (premi un bottone, selezioni una entry in una combo, ecc), esattamente come su Unreal Engine (un esempio è la modifica dello score nella widget class).
Certo, si potrebbe fare la stessa cosa con un oggetto, ma sarebbe più diretto.
Inoltre un “‘delegate” C++ è un oggetto molto interessante: si comporta come una funzione, ma in realtà si chiama un particolare metodo di un particolare oggetto.
Ovvero, sembrerebbe un unico puntatore, ma invece si tratta di una coppia (puntatore all’oggetto e puntatore al metodo di quella classe).
NB. Il delegate non va confuso con l’event
che, invece, è una lista di delegate.
I nostri corsi : https://www.develop4fun.it/premium-corsi-online-in-abbonamento
▼ SEGUICI SU ▼
» Facebook per il Web e corsi online: https://www.facebook.com/developforfun
» Facebook di D4F Games: https://www.facebook.com/d4fgames
» Instagram per il Web e corsi online: https://www.instagram.com/develop4fun
» Instagram di D4F Games: https://www.instagram.com/d4f_games
» Twitter per il Web e corsi online: https://twitter.com/Develop4fun
» Twitter di D4F Games: https://twitter.com/D4fGames
VISITA IL NOSTRO SITO WEB: https://www.develop4fun.it
ISCRIVITI SUBITO AL NOSTRO CANALE: https://www.youtube.com/channel/UCZ4dhshzpVbbRPVuL9TNH4Q