Delegati (Guida per programmatori C++)

24 Novembre 2022

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).

Esempio di Delegate in Unreal Engine 5
Esempio di Delegate in Unreal Engine 5. @Copyright Itamde Studio.

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://itamde.com/it/corsi-online-digitali/

▼ SEGUICI SU ▼
» Facebook: https://www.facebook.com/itamde
» Instagram: https://www.instagram.com/itamdestudio
» X (Twitter): https://x.com/itamdestudio
» ISCRIVITI SUBITO AL NOSTRO CANALE: https://www.youtube.com/channel/UCZ4dhshzpVbbRPVuL9TNH4Q

Articoli recenti

Commenti recenti

  1. Massimiliano Ferretti su I Commenti

    Mi permetto di aggiungere una mia considerazione personale che ho riportato dall'utilizzo di C#. Personalmente mi piace commentare funzioni e…

  2. Personalmente ritengo che utilizzare git porti sempre dei vantaggi anche per lo sviluppo solo. Già solo la possibilità di fare…

  3. ciao, il link a discord non è piu valido, vorrei utilizzare il materiale che hai pubblicato tempo fa, come faccio?

Itamde è anche una scuola di programmazione online.

Itamde

Impara ciò che desideri, al tuo ritmo

0 commenti

Invia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Potrebbe interessarti anche…

Medieval Minefield – Update 1.4 (Devlog)

Medieval Minefield – Update 1.4 (Devlog)

Un progetto iniziato nel 2021, ripreso oggi: cosa è cambiato, cosa stiamo sistemando, e dove stiamo andando Medieval Minefield è nato nel 2021 come esperimento “serio ma piccolo”: prendere la logica del campo minato classico, spostarla su mobile, e vestirla con una UI...

Rimani aggiornato sulle ultime notizie e novità

Accedi ai contenuti riservati

Scopri il dietro le quinte dei nostri progetti, risorse esclusive e lo stato di avanzamento delle nostre creazioni in tempo reale.

Iscriviti alla newsletter

Ricevi le nostre notizie, le nostre riflessioni creative e le novità dell’atelier direttamente nella tua casella di posta elettronica.

Seguici

Unisciti alla nostra community sui social network per seguire i nostri progetti quotidiani e interagire con noi.