C++/CLI
Paradygmat | |
---|---|
Typowanie | |
Twórca | |
Platforma sprzętowa | |
Platforma systemowa |
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;
}