Klasy i struktury odwołania (C++/CX)

Klasa C++/CX obsługuje zdefiniowane przez użytkownika klasy ref i struktury ref oraz klasy wartości zdefiniowane przez użytkownika i struktury wartości. Te struktury danych są podstawowymi kontenerami, za pomocą których język C++/CX obsługuje środowisko wykonawcze systemu Windows typu. Ich zawartość jest emitowana do metadanych zgodnie z określonymi określonymi regułami, co umożliwia ich przekazywane między składnikami środowisko wykonawcze systemu Windows i aplikacjami platforma uniwersalna systemu Windows napisanymi w języku C++ lub innych językach.

Klasa ref lub struktura ref ma następujące podstawowe funkcje:

  • Musi być zadeklarowana w przestrzeni nazw, w zakresie przestrzeni nazw, a w tej przestrzeni nazw może mieć publiczną lub prywatną dostępność. Tylko typy publiczne są emitowane do metadanych. Zagnieżdżone definicje klas publicznych nie są dozwolone, w tym zagnieżdżone publiczne klasy wyliczeń. Aby uzyskać więcej informacji, zobacz Namespaces (Przestrzenie nazw) i Type Visibility (Widoczność typów).

  • Może zawierać jako składowe C++/CX, w tym klasy ref, klasy wartości, struktury ref, struktury wartości lub struktury wartości dopuszczające wartość 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 jak lub klasę niestandardową, o ile std::vector nie są publiczne. Konstrukcje języka C++/CX mogą mieć public ułatwienia dostępu , , , lub protected internal private protected private . Wszystkie public elementy członkowskie lub są emitowane do protected metadanych. Standardowe typy języka C++ muszą mieć private internal typy , lub protected private accessibility, co uniemożliwia ich emitę do metadanych.

  • Może implementować co najmniej jedną klasę interfejsu lub struktury interfejsu.

  • Może 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ć zadeklarowany jako ogólny. Jeśli ma ona prywatną dostępność, może to być szablon.

  • Okres istnienia jest zarządzany przez automatyczne zliczanie odwoływać.

Deklaracji

Poniższy fragment kodu deklaruje Person klasę ref. Zwróć uwagę, że standardowy typ języka C++ jest używany w prywatnych składowych, a interfejs std::map środowisko wykonawcze systemu Windows jest używany w IMapView interfejsie publicznym. Zauważ również, że "^" jest dołączany do deklaracji typów referencyjnych.

// #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

Ten przykład kodu przedstawia 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żesz 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 istotnych różnic jest to, że nie można przypisać odwołania do śledzenia (%) do zmiennej zadeklarowanej przy użyciu semantyki stosu; Gwarantuje to, że liczba od referencyjnych wartości jest zmniejszana do zera, gdy funkcja kończy działanie. W tym przykładzie przedstawiono podstawową klasę Uri ref i funkcję, która używa jej z semantyką 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 przydziela się w pamięci dynamicznej przy użyciu słowa ref new kluczowego .

MyRefClass^ myClass = ref new MyRefClass();

Operator uchwytu do obiektu jest nazywany chłoniakiem i ^ zasadniczo jest inteligentnym wskaźnikiem języka C++. Pamięć, na która wskazuje, jest automatycznie niszczona, gdy ostatni czapa wykracza poza zakres lub jest jawnie ustawiona na nullptr wartość .

Z definicji klasa ref ma semantykę odwołania. Po przypisaniu zmiennej klasy ref jest to dojście, które jest kopiowane, a nie sam obiekt. W następnym przykładzie, po przypisaniu, zarówno , myClass jak i wskazują tę myClass2 samą lokalizację pamięci.

MyRefClass^ myClass = ref new MyRefClass();
MyRefClass^ myClass2 = myClass;

Po zainicjowaniu klasy ref języka C++/CX jej pamięć jest inicjowana od zera przed wywoływaniem jej konstruktora; w związku z tym nie jest konieczne do zera zainicjować poszczególnych elementów członkowskich, w tym właściwości. Jeśli klasa C++/CX pochodzi z klasy środowisko wykonawcze systemu Windows biblioteki C++ (WRL), tylko część klasy pochodnej C++/CX jest zainicjowana od zera.

Elementy członkowskie

Klasa ref może zawierać składowe funkcji , i ; tylko elementy członkowskie i public protected są emitowane do private public protected metadanych. Klasy zagnieżdżone i klasy ref są dozwolone, ale nie mogą być public . Pola publiczne są niedozwolone. publiczne elementy członkowskie danych muszą być zadeklarowane jako właściwości. Prywatne lub chronione składowe danych wewnętrznych mogą być polami. Domyślnie w klasie ref dostępność 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 ref lub struktura ref jest emitowana w metadanych, ale aby można było jej używać z innych aplikacji platforma uniwersalna systemu Windows i składników środowisko wykonawcze systemu Windows, musi ona mieć co najmniej jeden publiczny lub chroniony public konstruktor. Publiczna klasa ref, która ma publiczny konstruktor, musi być również zadeklarowana jako , aby zapobiec dalszej wyprowadzanie za pośrednictwem interfejsu binarnego sealed aplikacji (ABI).

Publiczne elementy członkowskie nie mogą być zadeklarowane const jako, ponieważ środowisko wykonawcze systemu Windows typ nie obsługuje const. Właściwość statyczna umożliwia zadeklarowanie publicznego członka danych przy użyciu wartości stałej.

Podczas definiowania publicznej klasy lub struktury ref kompilator stosuje wymagane atrybuty do klasy i zapisuje te informacje w pliku winmd aplikacji. Jednak w przypadku definiowania niezaeznaną publiczną klasę ref ręcznie zastosuj atrybut , aby upewnić się, że klasa nie jest widoczna dla aplikacji platforma uniwersalna systemu Windows napisanych w Windows::Foundation::Metadata::WebHostHidden języku JavaScript.

Klasa ref może mieć standardowe typy języka C++, w tym const typy, w dowolnym private internal , lub protected private składowych.

Publiczne klasy ref, które mają parametry typu, są niedozwolone. Zdefiniowane przez użytkownika ogólne klasy odmów są niedozwolone. Prywatna, wewnętrzna lub chroniona prywatna klasa ref może być szablonem.

Destruktory

W języku C++/CX wywołanie metody w destruktorze publicznym wywołuje destruktor niezależnie od liczby delete odwoływać się do obiektu. To zachowanie umożliwia zdefiniowanie destruktora, który wykonuje niestandardowe oczyszczanie zasobów innych niż RAII w sposób deterministyczny. Jednak nawet w tym przypadku sam obiekt nie jest usuwany z pamięci. Pamięć obiektu jest wolnej tylko wtedy, gdy liczba odwoływać osiągnie zero.

Jeśli destruktor klasy nie jest publiczny, jest wywoływany tylko wtedy, gdy liczba odwoływać osiągnie zero. Jeśli wywołasz na obiekcie, który ma destruktor prywatny, kompilator zgłasza ostrzeżenie C4493, które mówi", że wyrażenie delete nie ma żadnego wpływu, ponieważ destruktor obiektu nie ma delete <type name> "publicznej" dostępności".

Destruktory klas ref można zadeklarować tylko w następujący sposób:

  • publiczne i wirtualne (dozwolone w typach zapieczętowanych lub niezapieczętowanych)

  • chronione prywatne i niewirtualne (dozwolone tylko dla niezabłysowanych typów)

  • prywatne i niewirtualne (dozwolone tylko dla typów zapieczętowanych)

Nie jest dozwolona żadna inna kombinacja ułatwień dostępu, wirtualizacji i zapieczętowości. Jeśli destruktor nie zostanie jawnie zadeklarowany, kompilator wygeneruje publiczny destruktor wirtualny, jeśli klasa bazowa typu lub dowolny członek ma publiczny destruktor. W przeciwnym razie kompilator generuje chroniony prywatny destruktor niewirtualny dla niezapieczętowanych typów lub prywatny destruktor niewirtualny dla typów zapieczętowanych.

Zachowanie jest niezdefiniowane, jeśli próbujesz uzyskać dostęp do składowych klasy, która ma już uruchomiony destruktor; Najprawdopodobniej spowoduje to awarię programu. Wywołanie delete t w typie, który nie ma publicznego destruktora, nie ma żadnego efektu. Wywołanie klasy typu lub klasy bazowej, która ma znany delete this lub private destruktor z hierarchii typów, protected private również nie ma żadnego efektu.

Podczas deklarowania publicznego destruktora kompilator generuje kod tak, aby klasa ref implementował, a Platform::IDisposable destruktor implementował Dispose metodę . Platform::IDisposable to projekcja języka C++/CX dla Windows::Foundation::IClosable . Nigdy jawnie nie implementuj tych interfejsów.

Dziedziczenie

Platform::Object jest uniwersalną klasą bazową dla wszystkich klas ref. Wszystkie klasy ref są niejawnie konwertowane na platform::Object i mogą przesłaniać obiekt::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ć go Windows::UI::Xaml::DependencyObject jako klasy bazowej.

Po zdefiniowanym niezabłyszonej klasie, która dziedziczy z klasy , inne publiczne lub prywatne klasy ref w składniku lub aplikacji mogą MyBase DependencyObject dziedziczyć z klasy MyBase . Dziedziczenie w publicznych klasach ref powinno być wykonywane tylko w celu obsługi przesłonięcia metod wirtualnych, tożsamości polimorficznej i hermetyzacji.

Prywatna podstawowa klasa ref nie jest wymagana do wyprowadzenia z istniejącej niezapiekałej klasy. Jeśli potrzebujesz hierarchii obiektów do modelowania własnej struktury programu lub włączenia ponownego użycia kodu, użyj prywatnych lub wewnętrznych klas ref lub, jeszcze lepiej, standardowych klas C++. Funkcje hierarchii obiektów prywatnych można uwidocznić za pomocą publicznej zapieczętowanej otoki klasy ref.

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 dziedziczenia klas napisanych w innych językach, takich jak C# lub Visual Basic, z typów zadeklarowanych w składniku języka środowisko wykonawcze systemu Windows napisanym w języku C++/CX.

Poniżej znajdują się podstawowe reguły dziedziczenia w języku C++/CX:

  • Klasy ref mogą dziedziczyć bezpośrednio z co najwyżej jednej bazowej klasy ref, ale mogą implementować dowolną liczbę interfejsów.

  • Jeśli klasa ma publiczny konstruktor, musi być zadeklarowana jako zapieczętowana, aby zapobiec dalszemu wyprowadzanie.

  • Można tworzyć publiczne niezapiekane klasy bazowe z wewnętrznymi lub chronionymi konstruktorami prywatnymi, pod warunkiem, że klasa bazowa pochodzi bezpośrednio lub pośrednio z istniejącej niezapiekałej 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 tworzyć na podstawie zdefiniowanej przez użytkownika bazowej klasy ref tylko w ramach tego samego środowisko wykonawcze systemu Windows lub platforma uniwersalna systemu Windows aplikacji.

  • W przypadku klas ref obsługiwane jest tylko dziedziczenie publiczne.

    ref class C{};
    public ref class D : private C //Error C3628
    {};
    

Poniższy przykład pokazuje, 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
Odwołanie do języka C++/CX
Odwołania do przestrzeni nazw