Classes et structures de référence (C++/CX)

C++/CX prend en charge les classes ref définies par l’utilisateur et les structs ref, ainsi que les classes de valeur définies par l’utilisateur et les structs de valeur. Ces structures de données sont les conteneurs principaux par lesquels C++/CX prend en charge le système de type Windows Runtime. Leur contenu est émis dans les métadonnées en fonction de certaines règles spécifiques, ce qui leur permet de passer entre les composants Windows Runtime et les applications plateforme Windows universelle écrites en C++ ou dans d’autres langues.

Une classe ref ou un struct ref comporte les caractéristiques essentielles suivantes :

  • Elle/il doit être déclaré(e) dans un espace de noms, dans la portée de l'espace de noms. En outre, au sein de cet espace de noms, elle/il peut disposer d'un accès public ou privé. Seuls les types publics sont émis vers les métadonnées. Les définitions de classes publiques imbriquées ne sont pas autorisées, notamment les classes enum publiques imbriquées. Pour plus d’informations, consultez Espaces de noms et Visibilité de type.

  • Il peut contenir en tant que membres C++/CX, y compris les classes ref, les classes de valeur, les structs ref, les structs de valeur ou les structs de valeur Nullable. Il peut également contenir des types scalaires tels que float64, boolet ainsi de suite. Elle/il peut également contenir des types C++ standard tels que std::vector ou une classe personnalisée, tant qu'ils ne sont pas publics. Les constructions C++/CX peuvent avoir public, , protected, internalprivateou protected private accessibilité. Tous les membres public ou protected sont émis vers les métadonnées. Les types C++ standard doivent avoir une accessibilité private, internalou protected private , ce qui les empêche d'être émis vers les métadonnées.

  • Elle peut implémenter une ou plusieurs classes d'interface ou structures d'interface.

  • Elle peut hériter d'une classe de base, et les classes de base elles-mêmes ont des restrictions supplémentaires. L'héritage dans les hiérarchies de classes ref publiques comporte plus de restrictions que l'héritage dans les classes ref privées.

  • Il ne peut être déclaré comme générique. S'il a une accessibilité privée, il peut s'agir d'un modèle.

  • Sa durée de vie est gérée par un comptage de références automatique.

Déclaration

Le fragment de code suivant déclare la classe ref Person . Notez que le type C++ std::map standard est utilisé dans les membres privés et que l’interface Windows Runtime IMapView est utilisée dans l’interface publique. Notez également que « ^ » est ajouté aux déclarations de types de référence.

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

Implémentation

Cet exemple de code montre une implémentation de la classe ref Person :

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

Utilisation

L'exemple de code suivant montre comment le code client utilise la classe ref Person .

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

Vous pouvez également utiliser la sémantique de pile pour déclarer une variable de classe ref locale. Un tel objet se comporte comme une variable de pile même si la mémoire est toujours allouée dynamiquement. Une différence importante est que vous ne pouvez pas assigner une référence de suivi (%) à une variable qui est déclarée à l'aide de la sémantique de pile, ce qui garantit que le nombre de références est décrémenté à zéro lorsque la fonction s'arrête. Cet exemple montre un Uride classe ref de base et une fonction qui l'utilise avec la sémantique de pile :

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

Gestion de la mémoire

Vous pouvez allouer une classe ref dans la mémoire dynamique à l'aide du mot clé ref new .

MyRefClass^ myClass = ref new MyRefClass();

L’opérateur ^ handle-to-object est appelé chapeau et est fondamentalement un pointeur intelligent C++. La mémoire vers laquelle il pointe est automatiquement détruite lorsque le dernier chapeau se trouve hors de portée ou est défini explicitement dans nullptr.

Par définition, une classe ref comporte la sémantique de référence. Lorsque vous assignez une variable de classe ref, c'est le handle qui est copié et non l'objet lui-même. Dans l'exemple suivant, après l'assignation, myClass et myClass2 pointent toutes les deux vers le même emplacement de mémoire.

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

Quand une classe ref C++/CX est instanciée, sa mémoire est initialisée à zéro avant que son constructeur ne soit appelé ; ainsi, il n'est pas nécessaire d'initialiser à zéro les membres individuels, propriétés incluses. Si la classe C++/CX dérive d'une classe WRL (Windows Runtime C++ Library), seule la partie de la classe C++/CX dérivée est initialisée à zéro.

Membres

Une classe ref peut contenir des membres de fonction public, protectedet private . Seuls les membres public et protected sont émis vers les métadonnées. Les classes imbriquées et les classes ref sont autorisées mais ne peuvent pas être public. Les champs publics ne sont pas autorisés ; les données membres publiques doivent être déclarées comme des propriétés. Les membres de données internes privés ou protégés peuvent être des champs. Par défaut, dans une classe ref, l'accessibilité de tous les membres est private.

Un struct ref (structure de référence) est identique à une classe ref, sauf que ses membres ont par défaut une accessibilité public .

Une classe ref ou un public struct ref est émis dans les métadonnées, mais pour être utilisable à partir d’autres applications plateforme Windows universelle et des composants Windows Runtime, il doit avoir au moins un constructeur public ou protégé. Une classe ref publique qui comporte un constructeur public doit être également déclarée comme sealed pour éviter toute dérivation ultérieure via l'interface binaire d'application (ABI, Application Binary Interface).

Les membres publics peuvent ne pas être déclarés comme const étant donné que le système de type Windows Runtime ne prend pas en charge const. Vous pouvez utiliser une propriété statique pour déclarer des données membres publiques avec une valeur constante.

Lorsque vous définissez une classe ref publique ou un struct ref public, le compilateur applique les attributs nécessaires à la classe et stocke ces informations dans le fichier .winmd de l'application. Toutefois, lorsque vous définissez une classe ref non scellée publique, appliquez manuellement l’attribut Windows::Foundation::Metadata::WebHostHidden pour vous assurer que la classe n’est pas visible pour plateforme Windows universelle applications écrites en JavaScript.

Une classe ref peut avoir des types standard C++, notamment des types const , dans tout membre private, internalou protected private .

Les classes ref publiques qui ont des paramètres de type ne sont pas autorisées. Les classes ref génériques définies par l'utilisateur ne sont pas autorisées. Une classe ref privée, interne ou protégée peut être un modèle.

Destructeurs

Dans C++/CX, l’appel delete d’un destructeur public appelle le destructeur, quel que soit le nombre de références de l’objet. Ce comportement vous permet de définir un destructeur qui effectue un nettoyage personnalisé des ressources autres que RAII (Resource Acquisition Is Initialization) de façon déterministe. Toutefois, même dans ce cas, l'objet lui-même n'est pas supprimé de la mémoire. La mémoire de l'objet est libérée uniquement lorsque le nombre de références atteint zéro.

Si le destructeur d'une classe n'est pas public, il est uniquement appelé lorsque le nombre de références atteint zéro. Si vous appelez delete un objet qui a un destructeur privé, le compilateur déclenche l’avertissement C4493, qui indique « l’expression delete n’a aucun effet, car le destructeur du nom> de <type n’a pas d’accessibilité publique ».

Les destructeurs de classe ref peuvent être déclarés uniquement comme suit :

  • publics et virtuels (autorisés sur les types verrouillés ou déverrouillés/ouverts)

  • privés protégés et non virtuels (uniquement autorisés sur les types déverrouillés)

  • privés et non virtuels (autorisés uniquement sur les types verrouillés)

Il ne fournit aucune autre combinaison d'accessibilité, de virtualité et de verrouillage. Si vous ne déclarez pas explicitement un destructeur, le compilateur génère un destructeur virtuel public si la classe de base ou un membre du type comporte un destructeur public. Sinon, le compilateur génère un destructeur non virtuel privé protégé pour les types déverrouillés, ou un destructeur non virtuel privé pour les types verrouillés.

Le comportement n'est pas défini si vous tentez d'accéder aux membres d'une classe dont le destructeur a déjà été exécuté ; il provoquera très probablement l'arrêt système du programme. Appeler delete t sur un type qui ne comporte aucun destructeur public n'a aucun effet. Appeler delete this sur un type ou une classe de base qui comporte un destructeur private ou protected private connu à partir de sa hiérarchie de types n'a également aucun effet.

Lorsque vous déclarez un destructeur public, le compilateur génère le code afin que la classe ref implémente Platform::IDisposable et que le destructeur implémente la méthode Dispose . Platform::IDisposable est la projection C++/CX de Windows::Foundation::IClosable. N'implémentez jamais explicitement ces interfaces.

Héritage

Platform::Object est la classe de base universelle pour toutes les classes ref. Toutes les classes ref sont implicitement convertibles en Platform::Object et peuvent remplacer Object::ToString. Toutefois, le modèle d’héritage Windows Runtime n’est pas destiné à être un modèle d’héritage général ; dans C++/CX, cela signifie qu’une classe ref publique définie par l’utilisateur ne peut pas servir de classe de base.

Si vous créez un contrôle utilisateur XAML et que l'objet participe au système de propriétés de dépendance, vous pouvez utiliser Windows::UI::Xaml::DependencyObject comme classe de base.

Après avoir défini une classe MyBase déverrouillée qui hérite de DependencyObject, d'autres classes ref publiques ou privées de votre composant ou de votre application peuvent hériter de MyBase. L'héritage dans les classes ref publiques doit être effectué pour prendre en charge des substitutions de méthodes virtuelles, d'identités polymorphes et d'encapsulation.

Une classe ref de base privée n'est pas obligatoire pour dériver d'une classe non verrouillée existante. Si vous avez besoin d'une hiérarchie d'objets pour modéliser votre propre structure de programme ou pour activer la réutilisation de code, utilisez les classes ref privées ou internes, ou mieux encore, les classes C++ standard. Vous pouvez exposer la fonctionnalité de la hiérarchie d'objets privée via un wrapper de classe ref verrouillée publique.

Une classe ref qui a un constructeur public ou protégé dans C++/CX doit être déclarée comme scellée. Cette restriction signifie qu’il n’existe aucun moyen pour les classes écrites dans d’autres langages tels que C# ou Visual Basic d’hériter des types que vous déclarez dans un composant Windows Runtime écrit en C++/CX.

Voici les règles de base pour l’héritage en C++/CX :

  • Les classes ref peuvent hériter directement au plus d'une classe ref de base, mais peuvent implémenter un nombre quelconque d'interfaces.

  • Si une classe est dotée d'un constructeur public, elle doit être déclarée comme verrouillée pour empêcher une dérivation supplémentaire.

  • Vous pouvez créer des classes de base déverrouillée qui ont des constructeurs privés ou internes protégés, à condition que la classe de base dérive directement ou indirectement d'une classe de base déverrouillée existante comme Windows::UI::Xaml::DependencyObject. L'héritage de classes ref définies par l'utilisateur dans les fichiers .winmd n'est pas pris en charge ; toutefois, une classe ref peut hériter d'une interface définie dans un autre fichier .winmd. Vous pouvez créer des classes dérivées à partir d’une classe ref de base définie par l’utilisateur uniquement dans le même composant Windows Runtime ou plateforme Windows universelle application.

  • Pour les classes ref, seul l'héritage public est pris en charge.

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

L'exemple suivant montre comment exposer une classe ref publique qui dérive d'autres classes ref dans une hiérarchie d'héritage.

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

Voir aussi

Système de type
Classes et structures de valeur
Informations de référence sur le langage C++/CX
Référence aux espaces de noms