Udostępnij za pośrednictwem


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, booli tak dalej. Może również zawierać standardowe typy języka C++, takie jak std::vector lub klasa niestandardowa, o ile nie są publiczne. Konstrukcje języka C++/CX mogą mieć publicułatwienia dostępu , protected, internal, privatelub protected private . Wszystkie public elementy członkowskie lub protected są emitowane do metadanych. Typy języka C++ w warstwie Standardowa muszą mieć privateułatwienia dostępu, internalprotected 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ń.

Deklaracji

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ę Uriref 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 nullptrwartość .

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.

Członkowie

Klasa ref może zawierać publicskładowe funkcji , protectedi 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 privateelementach członkowskich , internallub 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 DependencyObjectklasy MyBase , inne publiczne lub prywatne klasy ref w składniku lub aplikacji mogą dziedziczyć z MyBaseklasy . 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