C++/CLI

C++/CLI
Paradygmat

wieloparadygmatowy

Typowanie

statyczne

Twórca

Microsoft

Platforma sprzętowa

.NET Framework

Platforma systemowa

wieloplatformowy

C++/CLI (Common Language Infrastructure) to język programowania oparty na C++, stworzony przez Microsoft w celu zastąpienia Managed Extensions for C++. Składnia rozszerzeń C++/CLI została zbudowana od nowa, przez co zapewnia znacznie większą czytelność kodu niż składnia Managed C++. Tak jak platforma .NET, C++/CLI jest standaryzowany przez ECMA. Na razie jedyny kompilator obsługujący go to Visual C++ w wersjach od 2005, włączając w to edycje Express.

C++/CLI (tak jak wcześniej Managed C++) jako jedyny z języków .NET umożliwia dowolne używanie razem kodu natywnego i zarządzanego. Odwoływanie się do natywnego kodu C++ w innych językach .NET jest możliwe tylko przez PInvoke lub COM, metody dosyć powolne i bardziej skomplikowane. Dlatego C++/CLI jest często używany jako pomost między .NET a natywnym kodem, na przykład umożliwiając tworzenie klas opakowujących zwykły kod C++ i udostępniających go dla wszystkich innych języków .NET. Maszyna Mono nie obsługuje tego mieszanego kodu (mixed-mode assembly) generowanego przez kompilator C++/CLI.

Zmiany w stosunku do Managed Extensions for C++

W przeciwieństwie do Managed C++, będącego ścisłym rozszerzeniem C++ (ze słowami kluczowymi jak __gc czy __value), C++/CLI jest uznawany za osobny język. Z tego powodu dokonano wielu znacznych zmian w składni.

Wiele nieścisłości w składni, jak na przykład różne działanie jednego operatora new() w Managed C++, zostało rozdzielonych: w C++/CLI zarządzane typy danych są tworzone nowym operatorem gcnew. Poza tym w C++/CLI dostępne są typy generyczne (oparte na szablonach języka C#).

W Managed C++ istniały dwa rodzaje wskaźników: __nogc - zwyczajne wskaźniki z C++ oraz __gc - wskaźniki działające na typach zarządzanych z .NET. W C++/CLI jedyny typ wskaźnika to zwykły wskaźnik C++, a zarządzane typy z .NET są odwoływane przez "uchwyty", z nową składnią NazwaKlasy^ zamiast NazwaKlasy*. To rozróżnienie jest najbardziej przydatne gdy mieszany jest kod natywny i zarządzany; pozwala na szybką identyfikację, które obiekty działają pod odśmiecaczem .NET, a które muszą być ręcznie usuwane.

Finalizatory

Kolejną zmianą w C++/CLI jest składnia finalizatora !NazwaKlasy() - specjalnego niedeterministycznego destruktora, który jest uruchamiany, gdy obiekt ma zostać zniszczony w ramach działania odśmiecacza.

Deterministyczny destruktor ~NazwaKlasy() jest tłumaczony przez kompilator jako wypełnienie metody Dispose() interfejsu IDisposable. Niedeterministyczny destruktor dziedziczy z metody Finalize() bazowej klasy Object.

Deterministyczny destruktor powinien być używany, gdy istnieje potrzeba zwolnienia niezarządzanych zasobów lub zasobów całego systemu (połączenia sieciowe, strumienie plików itp.). W innych przypadkach powinien wystarczyć finalizator. Jeżeli jest używany deterministyczny destruktor, programista powinien tworzyć finalizator, który tylko sprawdza czy destruktor został już wykonany i jeżeli nie został, powinien wykonać go (by uniknąć możliwych wycieków niezarządzanej pamięci/zasobów).

Przykładowy program

Poniższy program wyświetla napis "Hello World – Managed" przy użyciu funkcji .NET i napis "Hello World – Native" przy użyciu zwykłej biblioteki standardowej C++.

 #include <iostream>
 
 using namespace System;
 using namespace std; // Przestrzeń nazw standardowej biblioteki języka C++
 
 int main(array<System::String ^> ^args)
 {
     Console::WriteLine(L"Hello World - Managed");
     cout << "Hello World - Native"; // Wysyłanie podanego tekstu na standardowe wyjście - domyślnie na konsolę/terminal
     return 0;
 }