C++/CLI

Da Wikipedia, l'enciclopedia libera.
Jump to navigation Jump to search

C++/CLI (C++ modificato per la Common Language Infrastructure) è un linguaggio di programmazione specifico creato da Microsoft e destinato a sostituire le Managed extensions per C++. Si tratta di una revisione completa che mira a semplificare la vecchia sintassi del Managed C++, ora deprecato.[1] C++/CLI è stato standardizzato da Ecma come ECMA-372. È disponibile in Visual Studio 2005, 2008, 2010, 2012, 2013 e 2015, incluse le versioni Express.

Cambiamenti sintattici[modifica | modifica wikitesto]

C++/CLI è concepito come un linguaggio a sé stante, (ad esempio con un nuovo insieme di parole chiave), a differenza del Managed C++ (MC++), che è piuttosto un superset del C++ in cui le parole chiave non standard erano identifcate con __gc o __value. Di conseguenza, introduce alcune importanti modifiche sintattiche, legate principalmente all'eliminazione di identificatori ambigui e all'aggiunta di funzionalità specifiche NET.

Molte sintassi in conflitto, come le versioni multiple dell'operatore new() in MC++, sono state separate: nel C++/CLI e in .NET i tipi di riferimento vengono creati con la nuova parola chiave gcnew (che sta per garbage collected new ()). Inoltre, C++/CLI ha introdotto il concetto dei generici da .NET (simile, per gli scopi più comuni, ai template standard C++, ma molto diversi nella loro implementazione).

Handles[modifica | modifica wikitesto]

In MC++, vi erano due diversi tipi di puntatori: i puntatori __nogc, essenzialmente ordinari puntatori C++, e i puntatori __gc, usati per i tipi di riferimento .NET. Nel C++/CLI, invece, l'unico tipo di puntatore è il normale puntatore C++, mentre i tipi di riferimento .NET sono accessibili attraverso un handle usando la nuova sintassi ClassName^ invece di ClassName*. Questo nuovo costrutto è particolarmente utile quando il codice contiene insieme codice C++ standard e codice gestito; consente di rendere chiaro quali sono gli oggetti gestiti dal garbage collection automatico di .NET e quali sono invece gli oggetti che il programmatore deve distruggere in modo esplicito.

Rintracciamento di riferimenti[modifica | modifica wikitesto]

Un rintracciamento di riferimenti (anche detto tracking references) in C++/CLI è un handle di una variabile passata per riferimento. Come concetto è simile all'utilizzo di *& (riferimento a un puntatore) nel C++ classico, e (nella dichiarazione di funzioni) corrisponde alla parola chiave ref applicata a tipi in C#, o ByRef in .NET. Per indicare un rintracciamento di riferimento il C++/CLI utilizza come sintassi ^%.

Un esempio sull'utilizzo del 'rintracciamento di riferimenti' viene mostrato nel codice che segue. Rimpiazzare il rintracciamento di riferimenti con un handle regolare lascerebbe l'array di stringhe risultante con 10 stringhe handles non inizializzate, in quanto sarebbero impostate solamente le stringhe handle nell'array, dato che vengono passate per valore e non per riferimento.

int main()
{
    array<String^> ^arr = gcnew array<String^>(10);
    int i = 0;

    for each(String^% s in arr) {
        s = i++.ToString();
    }

    return 0;
}

Si noti che in C# tale construtto non sarebbe permesso, dato che non permette il passaggio di valori per riferimento mediante cicli foreach . Pertanto occorrerebbe una soluzione secondaria o temporanea.

Finalizzatori e variabili automatiche[modifica | modifica wikitesto]

Un'ulteriore differenza con C++/CLI è l'introduzione sintattica di finalizzatori !ClassName, un tipo speciale di distruttore non deterministico eseguito come parte della garbage collection routine. La sintassi dei distruttori classica del C++, quale ~ClassName(), esiste anche per oggetti gestiti, e riflette meglio la semantica "tradizionale" del C++ di una distruzione deterministica (di fatto i distruttori possono essere invocati a livello di codice mediante delete .

Nel paradigma .NET naturale, il modello di distruzione non deterministico annulla il metodo protetto Finalize della classe root Object; mentre il modello determinstico è implementato attraverso il metodo Dispose dell'interfaccia IDisposable (che il compilatore C++/CLI trasforma in un distruttore). Oggetti provenienti da C# o VB.NET, che annullano il metodo Dipose, possono essere posti manualmente in C++/CLI mediante delete, esattamente come le classi .NET in C++/CLI.

// C++/CLI
ref class MiaClasse{
public:
    MiaClasse();  // costruttore
    ~MiaClasse(); // distruttore (deterministico) (implementato come IDisposable.Dispose())
protected:
    !MiaClasse(); // finalizzatore (distruttore non-deterministico) (implemented as Finalize())

public:
    static void Test(){
        MiaClasse automatic; // Non un handle, e non inizializzato: il compilatore invoca qui il costruttore

        MiaClasse ^user = gcnew MiaClasse();
        delete user;

        // Il compilatore invoca il distruttore automatico quando l'automatico esce dalla visibilità (scope)
    }
};

Operatore di overloading[modifica | modifica wikitesto]

Un operatore di overloading (o di sovraccarico) funziona esattamente come nel C++ classico. Ogni * diventa un ^, ogni & diventa un %, con il resto della sintassi completamente invariato, con un'eccezione: per le classi .NET, l'operatore di overloading è instanziabile e invocabile non solo per le classi stesse, ma anche per i riferimenti alle classi. Tale peculiarità è necessaria per dare a ref class la semantica per l'operatore di overloading che le ref classes .NET si aspettano (Al contrario, questo significa anche che le ref classes presenti nel framework .NET fanno riferimento operatori di overloading, spesso implicitamente implementati in C++/CLI.

Per esempio, facendo un paragone tra due Stringhe di riferimento (String^) mediante l'operatore == restituirà "true" (vero) a prescindere. Essendo l'operatore di overloading statico, effettuare un cast a Object^ rimuove la semantica di overloading.

//effetti sulla referenza dell'operatore di overloading
String ^s1 = "abc";
String ^s2 = "ab" + "c";
Object ^o1 = s1;
Object ^o2 = s2;
s1 == s2; // true, perché riferiscono allo stesso oggetto
o1 == o2; // false, perché non sono lo stesso oggetto

C++/CX[modifica | modifica wikitesto]

Il nuovo C++/CX con l'obiettivo di WinRT, sebbene produca interamente codice "unmanaged", prende in prestito il concetto di ref e la sintassi ^ per la referenza sul conteggio delle componenti di WinRT, che sono simili agli oggetti COM.[2]

Note[modifica | modifica wikitesto]

Collegamenti esterni[modifica | modifica wikitesto]

Template:Common Language Infrastructure Template:Ecma International Standards