Klasy i struktury odwołania (C++/CX)
Język C++/CX obsługuje klasy ref zdefiniowane przez użytkownika i struktury ref oraz klasy wartości zdefiniowane przez użytkownika i struktury wartości. Te struktury danych to podstawowe kontenery, za pomocą których język C++/CX obsługuje system typów środowisko wykonawcze systemu Windows. Ich zawartość jest emitowana do metadanych zgodnie z określonymi regułami i umożliwia ich przekazywanie między składnikami środowisko wykonawcze systemu Windows a aplikacjami platforma uniwersalna systemu Windows napisanymi w języku C++ lub innymi językami.
Klasa ref lub struktura ref ma następujące podstawowe funkcje:
Musi być zadeklarowana w przestrzeni nazw, w zakresie przestrzeni nazw i w tej przestrzeni nazw może mieć dostęp publiczny lub prywatny. Tylko typy publiczne są emitowane do metadanych. Zagnieżdżone definicje klas publicznych nie są dozwolone, w tym zagnieżdżone publiczne klasy wyliczenia . Aby uzyskać więcej informacji, zobacz Przestrzenie nazw i Widoczność typu.
Może zawierać jako elementy członkowskie C++/CX, w tym klasy ref, klasy wartości, struktury ref, struktury wartości lub struktury wartości dopuszczanej do wartości null. Może również zawierać typy skalarne, takie jak
float64
,bool
i tak dalej. Może również zawierać standardowe typy języka C++, takie jakstd::vector
lub klasa niestandardowa, o ile nie są publiczne. Konstrukcje języka C++/CX mogą miećpublic
ułatwienia dostępu ,protected
,internal
,private
lubprotected private
. Wszystkiepublic
elementy członkowskie lubprotected
są emitowane do metadanych. Typy języka C++ w warstwie Standardowa muszą miećprivate
ułatwienia dostępu,internal
protected private
które uniemożliwiają ich emitowanie do metadanych.Może implementować co najmniej jedną klasę interfejsu lub struktury interfejsu.
Może ona dziedziczyć z jednej klasy bazowej, a same klasy bazowe mają dodatkowe ograniczenia. Dziedziczenie w publicznych hierarchiach klas ref ma więcej ograniczeń niż dziedziczenie w prywatnych klasach ref.
Może nie być zadeklarowana jako ogólna. Jeśli ma ona dostęp prywatny, może to być szablon.
Jego okres istnienia jest zarządzany przez automatyczne zliczanie odwołań.
Deklaracja
Poniższy fragment kodu deklaruje klasę Person
ref. Zwróć uwagę, że standardowy typ języka C++ std::map
jest używany w prywatnych elementach członkowskich, a interfejs środowisko wykonawcze systemu Windows IMapView
jest używany w interfejsie publicznym. Zwróć również uwagę, że element "^" jest dołączany do deklaracji typów odwołań.
// #include <map>
namespace WFC = Windows::Foundation::Collections;
namespace WFM = Windows::Foundation::Metadata;
[WFM::WebHostHidden]
ref class Person sealed
{
public:
Person(Platform::String^ name);
void AddPhoneNumber(Platform::String^ type, Platform::String^ number);
property WFC::IMapView<Platform::String^, Platform::String^>^ PhoneNumbers
{
WFC::IMapView<Platform::String^, Platform::String^>^ get();
}
private:
Platform::String^ m_name;
std::map<Platform::String^, Platform::String^> m_numbers;
};
Implementacja
W tym przykładzie kodu przedstawiono implementację Person
klasy ref:
#include <collection.h>
using namespace Windows::Foundation::Collections;
using namespace Platform;
using namespace Platform::Collections;
Person::Person(String^ name): m_name(name) { }
void Person::AddPhoneNumber(String^ type, String^ number)
{
m_numbers[type] = number;
}
IMapView< String^, String^>^ Person::PhoneNumbers::get()
{
// Simple implementation.
return ref new MapView< String^, String^>(m_numbers);
}
Użycie
W następnym przykładzie kodu pokazano, jak kod klienta używa Person
klasy ref.
using namespace Platform;
Person^ p = ref new Person("Clark Kent");
p->AddPhoneNumber("Home", "425-555-4567");
p->AddPhoneNumber("Work", "206-555-9999");
String^ workphone = p->PhoneNumbers->Lookup("Work");
Można również użyć semantyki stosu, aby zadeklarować lokalną zmienną klasy ref. Taki obiekt zachowuje się jak zmienna oparta na stosie, mimo że pamięć jest nadal przydzielana dynamicznie. Jedną z ważnych różnic jest to, że nie można przypisać odwołania śledzenia (%) do zmiennej zadeklarowanej przy użyciu semantyki stosu; Gwarantuje to, że liczba odwołań zostanie zdekrementowana do zera, gdy funkcja zakończy działanie. W tym przykładzie przedstawiono podstawową klasę Uri
ref i funkcję, która używa jej z semantykami stosu:
void DoSomething()
{
Windows::Foundation::Uri docs("http://docs.microsoft.com");
Windows::Foundation::Uri^ devCenter = docs.CombineUri("/windows/");
// ...
} // both variables cleaned up here.
Zarządzanie pamięcią
Klasę ref można przydzielić w pamięci dynamicznej przy użyciu słowa kluczowego ref new
.
MyRefClass^ myClass = ref new MyRefClass();
Operator ^
handle-to-object jest znany jako kapelusz i jest zasadniczo inteligentnym wskaźnikiem języka C++. Pamięć, do która wskazuje, jest automatycznie niszczona, gdy ostatni kapelusz wykracza poza zakres lub jest jawnie ustawiony na nullptr
wartość .
Z definicji klasa ref ma semantyka odwołań. Po przypisaniu zmiennej klasy ref jest to uchwyt, który jest kopiowany, a nie sam obiekt. W następnym przykładzie po przypisaniu zarówno, jak myClass
i myClass2
wskaż tę samą lokalizację pamięci.
MyRefClass^ myClass = ref new MyRefClass();
MyRefClass^ myClass2 = myClass;
Po utworzeniu wystąpienia klasy ref języka C++/CX jego pamięć jest inicjowana zero przed wywołaniem konstruktora; w związku z tym nie jest konieczne inicjowanie poszczególnych elementów członkowskich, w tym właściwości. Jeśli klasa C++/CX pochodzi z klasy środowisko wykonawcze systemu Windows C++ Library (WRL), tylko część klasy pochodnej C++/CX jest zerowa.
Elementy członkowskie
Klasa ref może zawierać public
składowe funkcji , protected
i private
; tylko public
elementy członkowskie i protected
są emitowane do metadanych. Zagnieżdżone klasy i klasy ref są dozwolone, ale nie mogą być public
. Pola publiczne są niedozwolone; elementy członkowskie danych publicznych muszą być zadeklarowane jako właściwości. Prywatne lub chronione wewnętrzne elementy członkowskie danych mogą być polami. Domyślnie w klasie ref ułatwienia dostępu wszystkich składowych to private
.
Struktura ref jest taka sama jak klasa ref, z tą różnicą, że domyślnie jej składowe mają public
ułatwienia dostępu.
Klasa public
ref lub struktura ref jest emitowana w metadanych, ale do użytku z innych aplikacji platforma uniwersalna systemu Windows i środowisko wykonawcze systemu Windows składników musi mieć co najmniej jeden publiczny lub chroniony konstruktor. Publiczna klasa ref, która ma publiczny konstruktor, musi być również zadeklarowana, sealed
aby zapobiec dalszemu wyprowadzaniu za pośrednictwem interfejsu binarnego aplikacji (ABI).
Publiczne elementy członkowskie mogą nie być deklarowane jakoconst
, ponieważ system typów środowisko wykonawcze systemu Windows nie obsługuje const. Możesz użyć właściwości statycznej, aby zadeklarować element członkowski danych publicznych z stałą wartością.
Podczas definiowania publicznej klasy ref lub struktury kompilator stosuje wymagane atrybuty do klasy i przechowuje te informacje w pliku winmd aplikacji. Jednak w przypadku definiowania publicznej niezaznaczonej klasy ref należy ręcznie zastosować Windows::Foundation::Metadata::WebHostHidden
atrybut, aby upewnić się, że klasa nie jest widoczna dla platforma uniwersalna systemu Windows aplikacji napisanych w języku JavaScript.
Klasa ref może mieć standardowe typy języka C++, w tym const
typy, w dowolnych private
elementach członkowskich , internal
lub protected private
.
Publiczne klasy ref, które mają parametry typu, są niedozwolone. Klasy ogólne ref zdefiniowane przez użytkownika nie są dozwolone. Prywatna, wewnętrzna lub chroniona prywatna klasa ref może być szablonem.
Destruktory
W języku C++/CX wywołanie delete
publicznego destruktora wywołuje destruktora niezależnie od liczby odwołań obiektu. To zachowanie umożliwia zdefiniowanie destruktora, który wykonuje niestandardowe czyszczenie zasobów innych niż RAII w sposób deterministyczny. Jednak nawet w tym przypadku sam obiekt nie jest usuwany z pamięci. Pamięć dla obiektu jest zwalniana tylko wtedy, gdy liczba odwołań osiągnie zero.
Jeśli destruktor klasy nie jest publiczny, jest wywoływany tylko wtedy, gdy liczba odwołań osiągnie zero. Jeśli wywołasz delete
obiekt, który ma prywatny destruktor, kompilator zgłasza ostrzeżenie C4493, co oznacza, że wyrażenie delete nie ma wpływu, ponieważ destruktor <nazwy> typu nie ma "publicznego" ułatwień dostępu.
Destruktory klas ref można zadeklarować tylko w następujący sposób:
publiczne i wirtualne (dozwolone w typach zapieczętowanych lub niezauczętowanych)
chronione prywatne i niewirtualne (dozwolone tylko w niezauczętowanych typach)
prywatne i niewirtualne (dozwolone tylko w przypadku zapieczętowanych typów)
Nie jest dozwolona żadna inna kombinacja ułatwień dostępu, wirtualizacji i zapieczętowania. Jeśli destruktor nie zostanie jawnie zadeklarowany, kompilator generuje publiczny destruktor wirtualny, jeśli klasa bazowa typu lub dowolny element członkowski ma publiczny destruktor. W przeciwnym razie kompilator generuje chroniony prywatny niewirtualny destruktor dla niezauczętowanych typów lub prywatnego destruktora niewirtualnego dla typów zapieczętowanych.
Zachowanie jest niezdefiniowane, jeśli próbujesz uzyskać dostęp do składowych klasy, która miała już jej działanie destruktora; najprawdopodobniej spowoduje awarię programu. Wywoływanie delete t
typu, który nie ma publicznego destruktora, nie ma żadnego wpływu. Wywołanie metody delete this
na typ lub klasę bazową, która ma znany private
lub protected private
destruktor z hierarchii typów, również nie ma żadnego wpływu.
Podczas deklarowania publicznego destruktora kompilator generuje kod, aby klasa ref implementowała Platform::IDisposable
i destruktor implementuje metodę Dispose
. Platform::IDisposable
to projekcja języka C++/CX klasy Windows::Foundation::IClosable
. Nigdy nie implementuj jawnie tych interfejsów.
Dziedziczenie
Platform::Object to uniwersalna klasa bazowa dla wszystkich klas ref. Wszystkie klasy ref są niejawnie konwertowane na platform::Object i mogą zastąpić object::ToString. Jednak model dziedziczenia środowisko wykonawcze systemu Windows nie jest przeznaczony jako ogólny model dziedziczenia; w języku C++/CX oznacza to, że zdefiniowana przez użytkownika publiczna klasa ref nie może służyć jako klasa bazowa.
Jeśli tworzysz kontrolkę użytkownika XAML, a obiekt uczestniczy w systemie właściwości zależności, możesz użyć Windows::UI::Xaml::DependencyObject
jej jako klasy bazowej.
Po zdefiniowaniu niezaużytej klasy dziedziczącej z DependencyObject
klasy MyBase
, inne publiczne lub prywatne klasy ref w składniku lub aplikacji mogą dziedziczyć z MyBase
klasy . Dziedziczenie w publicznych klasach ref powinno odbywać się tylko w celu obsługi przesłonięć metod wirtualnych, tożsamości polimorficznej i hermetyzacji.
Prywatna klasa ref bazy nie jest wymagana do wyprowadzenia z istniejącej niezaustawionej klasy. Jeśli chcesz, aby hierarchia obiektów modelować własną strukturę programu lub włączyć ponowne użycie kodu, użyj prywatnych lub wewnętrznych klas ref lub jeszcze lepiej, standardowych klas języka C++. Funkcje hierarchii obiektów prywatnych można uwidocznić za pomocą publicznej otoki klasy ref zapieczętowanej.
Klasa ref, która ma publiczny lub chroniony konstruktor w języku C++/CX, musi być zadeklarowana jako zapieczętowana. To ograniczenie oznacza, że nie ma możliwości, aby klasy napisane w innych językach, takich jak C# lub Visual Basic, dziedziczyły z typów zadeklarowanych w składniku środowisko wykonawcze systemu Windows napisanym w języku C++/CX.
Poniżej przedstawiono podstawowe reguły dziedziczenia w języku C++/CX:
Klasy ref mogą dziedziczyć bezpośrednio z co najwyżej jednej podstawowej klasy ref, ale mogą implementować dowolną liczbę interfejsów.
Jeśli klasa ma konstruktor publiczny, należy ją zadeklarować jako zapieczętowaną, aby zapobiec dalszemu wyprowadzaniu.
Można utworzyć publiczne niezaużytowane klasy bazowe, które mają wewnętrzne lub chronione konstruktory prywatne, pod warunkiem, że klasa bazowa pochodzi bezpośrednio lub pośrednio z istniejącej niezaustawionej klasy bazowej, takiej jak
Windows::UI::Xaml::DependencyObject
. Dziedziczenie klas ref zdefiniowanych przez użytkownika w plikach winmd nie jest obsługiwane; jednak klasa ref może dziedziczyć z interfejsu zdefiniowanego w innym pliku winmd. Klasy pochodne można utworzyć na podstawie klasy bazowej zdefiniowanej przez użytkownika tylko w ramach tego samego składnika środowisko wykonawcze systemu Windows lub aplikacji platforma uniwersalna systemu Windows.W przypadku klas ref obsługiwane jest tylko dziedziczenie publiczne.
ref class C{}; public ref class D : private C //Error C3628 {};
W poniższym przykładzie pokazano, jak uwidocznić publiczną klasę ref, która pochodzi z innych klas ref w hierarchii dziedziczenia.
namespace InheritanceTest2
{
namespace WFM = Windows::Foundation::Metadata;
// Base class. No public constructor.
[WFM::WebHostHidden]
public ref class Base : Windows::UI::Xaml::DependencyObject
{
internal:
Base(){}
protected:
virtual void DoSomething (){}
property Windows::UI::Xaml::DependencyProperty^ WidthProperty;
};
// Class intended for use by client code across ABI.
// Declared as sealed with public constructor.
public ref class MyPublicClass sealed : Base
{
public:
MyPublicClass(){}
//...
};
}
Zobacz też
System typów
Klasy i struktury wartości
Dokumentacja języka C++/CX
Dokumentacja przestrzeni nazw