Verweisklassen und Strukturen (C++/CX)

C++/CX unterstützt benutzerdefinierte Verweisklassen und Referenzstrukturen sowie benutzerdefinierte Wertklassen und Wertstrukturen. Diese Datenstrukturen sind die primären Container, mit denen C++/CX das Windows-Runtime Typsystem unterstützt. Ihre Inhalte werden gemäß bestimmten spezifischen Regeln an Metadaten ausgegeben, und dadurch können sie zwischen Windows-Runtime Komponenten und Universelle Windows-Plattform Apps übergeben werden, die in C++ oder anderen Sprachen geschrieben wurden.

Eine Verweisklasse oder Verweisstruktur hat die folgenden wesentlichen Funktionen:

  • Sie muss in einem Namespace und im Umfang des Namespace deklariert werden und darin eine öffentliche oder private Zugreifbarkeit bieten. Nur öffentliche Typen werden an Metadaten ausgegeben. Definitionen der geschachtelten öffentlichen Klasse sind nicht zulässig. Dies schließt geschachtelte öffentliche enum -Klassen ein. Weitere Informationen finden Sie unter Namespaces und Type Visibility.

  • Er kann als Member C++/CX enthalten, einschließlich Bezugsklassen, Wertklassen, Verweisstrukturen, Wertstrukturs- oder Nullwert-Strukturen. Es kann auch skalare Typen wie float64, bool, usw. enthalten. Sie kann auch Standard-C++-Typen wie std::vector oder eine benutzerdefinierte Klasse enthalten, sofern diese nicht öffentlich sind. C++/CX-Konstrukte können über publicBarrierefreiheit verfügen. protectedinternalprivateprotected private Alle public oder protected Member werden an Metadaten ausgegeben. Standard-C++-Typen müssen private, internaloder protected private Zugreifbarkeit aufweisen, um zu verhindern, dass sie an Metadaten ausgegeben werden.

  • Sie implementiert möglicherweise eine oder mehrere Schnittstellenklassen oder Schnittstellenstrukturen.

  • Sie kann jedoch von einer Basisklasse erben, und Basisklassen selbst haben weitere Einschränkungen. Vererbung in öffentlichen Verweisklassenhierarchien ist stärker eingeschränkt als Vererbung in privaten Verweisklassen.

  • Sie kann nicht als generisch deklariert werden. Wenn sie über eine private Zugreifbarkeit verfügt, ist es möglicherweise eine Vorlage.

  • Die Lebensdauer wird durch automatische Verweiszählung verwaltet.

Deklaration

Das folgende Codefragment deklariert die Person -Verweisklasse. Beachten Sie, dass der C++std::map-Standardtyp in den privaten Membern verwendet wird und die Windows-Runtime-Schnittstelle IMapView in der öffentlichen Schnittstelle verwendet wird. Beachten Sie außerdem, dass das "^" an die Deklaration von Verweistypen angefügt wird.

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

Implementierung

Dieses Codebeispiel zeigt eine Implementierung der Person -Verweisklasse.

#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);
}

Verwendung

Das nächste Codebeispiel zeigt, wie der Clientcode die Person -Verweisklasse verwendet.

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");

Sie können eine lokale Verweisklassenvariable auch deklarieren, indem Sie Stapelsemantik verwenden. Ein solches Objekt verhält sich wie eine stapelbasierte Variable, auch wenn der Arbeitsspeicher dennoch dynamisch zugeordnet wird. Ein wichtiger Unterschied besteht darin, dass Sie einer mit Stapelsemantik deklarierten Variablen keinen Nachverfolgungsverweis (%) zuweisen können. So wird gewährleistet, dass der Verweiszähler auf Null verringert ist, wenn die Funktion beendet wird. In diesem Beispiel wird eine Basisverweisklasse Uridargestellt sowie eine Funktion, die diese Klasse mit Stapelsemantik verwendet:

void DoSomething()
{
    Windows::Foundation::Uri docs("http://docs.microsoft.com");
    Windows::Foundation::Uri^ devCenter = docs.CombineUri("/windows/");
    // ... 
} // both variables cleaned up here.

Speicherverwaltung

Sie weisen einer Verweisklasse mit dem Schlüsselwort ref new dynamischen Speicher zu.

MyRefClass^ myClass = ref new MyRefClass();

Der Handle-to-Object-Operator ^ wird als Hut bezeichnet und ist grundsätzlich ein intelligenter C++-Zeiger. Der Speicher, auf den er zeigt, wird automatisch zerstört, sobald das letzte Dach den Gültigkeitsbereich verlässt oder ausdrücklich auf nullptrgesetzt wird.

Definitionsgemäß verfügt eine Verweisklasse über Verweissemantik. Wenn Sie eine Verweisklassenvariable zuweisen, wird das Handle kopiert, nicht das Objekt selbst. Im nächsten Beispiel zeigen myClass und myClass2 nach der Zuweisung beide auf die gleiche Speicheradresse.

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

Beim Instanziieren einer C++/CX-Verweisklasse wird ihr Speicher mit 0 (Null) initialisiert, bevor der Konstruktor aufgerufen wird. Daher müssen einzelne Member und auch Eigenschaften nicht mit 0 initialisiert werden. Wenn die C++/CX-Klasse von einer WRL-Klasse (Windows Runtime C++ Library) abgeleitet ist, wird nur der abgeleitete C++/CX-Klassenteil mit 0 initialisiert.

Member

Eine Verweisklasse kann Funktionsmember enthalten, die public, protectedund private sind. Nur public und protected Member werden in Metadaten ausgegeben. Geschachtelte Klassen und Verweisklassen sind zulässig, können jedoch nicht publicsein. Öffentliche Felder sind nicht zulässig; öffentliche Datenmember müssen als Eigenschaften deklariert werden. Private oder geschützte interne Datenmember können Felder sein. Standardmäßig ist in einer Verweisklasse die Zugreifbarkeit für alle Member private.

Eine Verweisstruktur ist das Gleiche wie eine Verweisklasse, nur dass auf ihre Member standardmäßig public zugegriffen werden kann.

Eine public Verweisklasse oder -struktur wird in Metadaten ausgegeben, kann jedoch von anderen Universelle Windows-Plattform Apps und Windows-Runtime Komponenten verwendet werden, die mindestens einen öffentlichen oder geschützten Konstruktor aufweisen müssen. Eine öffentliche Verweisklasse mit einem öffentlichen Konstruktor muss außerdem als sealed deklariert werden, um weitere Ableitungen über die Anwendungsbinärschnittstelle (ABI) zu verhindern.

Öffentliche Member werden möglicherweise nicht als const deklariert, da das Windows-Runtime Typsystem keine Const unterstützt. Sie können eine statische Eigenschaft verwenden, um einen öffentlichen Datenmember mit einem konstanten Wert zu deklarieren.

Wenn Sie eine öffentliche Verweisklasse oder Verweisstruktur definieren, ordnet der Compiler die erforderlichen Attribute für die Klasse zu und speichert diese Informationen in der WINMD-Datei der App. Wenn Sie jedoch eine öffentliche nicht deklarierte Referenzklasse definieren, wenden Sie das Windows::Foundation::Metadata::WebHostHidden Attribut manuell an, um sicherzustellen, dass die Klasse für Universelle Windows-Plattform Apps, die in JavaScript geschrieben wurden, nicht sichtbar ist.

Eine Verweisklasse kann über C++-Standardtypen (einschließlich const -Typen) in jedem Member verfügen, das private, internaloder protected private ist.

Öffentliche Verweisklassen, die über Typparameter verfügen, sind nicht zulässig. Benutzerdefinierte generische Verweisklassen sind nicht zulässig. Eine private, interne oder private geschützte Verweisklasse ist möglicherweise eine Vorlage.

Destruktoren

In C++/CX ruft das Aufrufen delete eines öffentlichen Destruktors den Destruktor unabhängig von der Referenzanzahl des Objekts auf. Durch dieses Verhalten können Sie einen Destruktor definieren, der eine benutzerdefinierte Bereinigung von nicht-RAII-Ressourcen in einer deterministischen Weise ausführt. Allerdings wird auch in diesem Fall das Objekt selbst nicht aus dem Arbeitsspeicher gelöscht. Der Speicher für das Objekt wird nur freigegeben, wenn der Verweiszähler null erreicht.

Ist der Destruktor einer Klasse nicht öffentlich, wird er nur aufgerufen, wenn der Verweiszähler null erreicht. Wenn Sie ein Objekt aufrufen delete , das über einen privaten Destruktor verfügt, löst der Compiler die Warnung C4493 aus, was besagt, dass der Löschausdruck keine Auswirkung hat, da der Destruktor des <Typnamens> keine "öffentliche" Barrierefreiheit aufweist.

Verweisklassendestruktoren können nur wie folgt deklariert werden:

  • öffentlich und virtuell (für versiegelte oder unversiegelte Typen)

  • geschützt privat und nicht virtuell (nur für unversiegelte Typen)

  • privat und nicht virtuell (nur für versiegelte Typen)

Keine andere Kombination von Zugreifbarkeit, Virtualität und Versiegelung ist zulässig. Wenn Sie nicht explizit einen Destruktor deklarieren, generiert der Compiler einen öffentlichen virtuellen Destruktor, wenn die Basisklasse des Typs oder ein Member einen öffentlichen Destruktor hat. Andernfalls generiert der Compiler einen geschützten, privaten und nicht virtuellen Destruktor für unversiegelte Typen oder einen privaten, nicht virtuellen Destruktor für versiegelte Typen.

Das Verhalten ist nicht definiert, wenn Sie versuchen, auf die Member einer Klasse zuzugreifen, deren Destruktor bereits ausgeführt wurde. Wahrscheinlich wird das Programm abstürzen. Das Aufrufen von delete t für einen Typ, der keinen öffentlichen Destruktor besitzt, hat keine Auswirkungen. Das Aufrufen von delete this für einen Typ oder eine Basisklasse, der bzw. die einen bekannten private - oder protected private -Destruktor besitzt, aus der Typhierarchie hat keine Auswirkungen.

Wenn Sie einen öffentlichen Destruktor deklarieren, generiert der Compiler den Code so, dass die Verweisklasse Platform::IDisposable implementiert und der Destruktor die Dispose -Methode implementiert. Platform::IDisposable ist die C++/CX-Projektion von Windows::Foundation::IClosable. Implementieren Sie niemals explizit diese Schnittstellen.

Vererbung

Platform::Object ist die universelle Basisklasse für alle Verweisklassen. Alle Verweisklassen sind implizit konvertierbar in Platform::Object und können Object::ToStringüberschreiben. Das Windows-Runtime Vererbungsmodell ist jedoch nicht als allgemeines Vererbungsmodell gedacht. In C++/CX bedeutet dies, dass eine benutzerdefinierte öffentliche Referenzklasse nicht als Basisklasse dienen kann.

Wenn Sie ein XAML-Benutzersteuerelement erstellen und das Objekt am Abhängigkeitseigenschaftensystem teilnimmt, können Sie Windows::UI::Xaml::DependencyObject als Basisklasse verwenden.

Nachdem Sie eine unversiegelte Klasse MyBase definiert haben, die von DependencyObjecterbt, können andere öffentliche oder private Verweisklassen in Ihrer Komponente oder App von MyBaseerben. Vererbung in öffentlichen Verweisklassen sollte nur vorgenommen werden, um Überschreibungen von Methoden, polymorphe Identität und Kapselung zu unterstützen.

Eine private Basisverweisklasse ist nicht erforderlich, um von einer vorhandenen unversiegelten Klasse abzuleiten. Wenn Sie eine Objekthierarchie benötigen, eine Ihre eigene Programmstruktur zu modellieren oder die Wiederverwendung von Code zu aktivieren, verwenden Sie private oder interne Verweisklassen, oder am besten Standard-C++-Klassen. Sie können die Funktionalität der privaten Objekthierarchie durch einen öffentlichen versiegelten Verweisklassenwrapper verfügbar machen.

Eine Verweisklasse mit einem öffentlichen oder geschützten Konstruktor in C++/CX muss als versiegelt deklariert werden. Diese Einschränkung bedeutet, dass es keine Möglichkeit für Klassen gibt, die in anderen Sprachen wie C# oder Visual Basic geschrieben wurden, von Typen zu erben, die Sie in einer Windows-Runtime Komponente deklarieren, die in C++/CX geschrieben wurde.

Hier sind die grundlegenden Regeln für die Vererbung in C++/CX:

  • Verweisklassen können direkt von höchstens einer Basisverweisklasse erben, jedoch können eine beliebige Anzahl von Schnittstellen implementieren.

  • Besitzt eine Klasse einen öffentlichen Konstruktor, muss als versiegelt deklariert werden, um eine weitere Ableitung zu verhindern.

  • Sie können öffentliche unversiegelte Basisklassen erstellen, die interne oder geschützte private Konstruktoren besitzen, vorausgesetzt, dass sich die Basisklasse direkt oder indirekt von einer vorhandenen unversiegelten Basisklasse wie Windows::UI::Xaml::DependencyObjectableitet. Vererbung von benutzerdefinierten Verweisklassen über WINMD-Dateien wird nicht unterstützt. Eine Verweisklasse kann jedoch von einer Schnittstelle erben, die in einer anderen WINMD-Datei definiert ist. Sie können abgeleitete Klassen aus einer benutzerdefinierten Basis ref-Klasse nur innerhalb derselben Windows-Runtime Komponente oder Universelle Windows-Plattform App erstellen.

  • Für Verweisklassen wird nur öffentliche Vererbung unterstützt.

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

Das folgende Beispiel zeigt, wie eine öffentliche Verweisklasse, die von anderen Verweisklassen abgeleitet wird, in einer Vererbungshierarchie verfügbar gemacht wird.

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(){}
        //...
    };
}

Siehe auch

Typsystem
Wertklassen und Strukturen
C++-/CX-Programmiersprachenreferenz
Referenz zu Namespaces