Conversions définies par l'utilisateur (C++/CLI)

Cette section décrit les conversions définies par l’utilisateur (UDC) quand l’un des types de la conversion est une référence ou une instance d’un type valeur ou référence.

Conversions implicites et explicites

Une conversion définie par l’utilisateur peut être implicite ou explicite. Un UDC doit être implicite si la conversion n’entraîne pas de perte d’informations. Sinon, un UDC explicite doit être défini.

Le constructeur d’une classe native peut être utilisé pour convertir une référence ou un type valeur en classe native.

Pour plus d’informations sur les conversions, consultez Boxing et Conversions standard.

// mcpp_User_Defined_Conversions.cpp
// compile with: /clr
#include "stdio.h"
ref class R;
class N;

value class V {
   static operator V(R^) {
      return V();
   }
};

ref class R {
public:
   static operator N(R^);
   static operator V(R^) {
      System::Console::WriteLine("in R::operator N");
      return V();
   }
};

class N {
public:
   N(R^) {
      printf("in N::N\n");
   }
};

R::operator N(R^) {
   System::Console::WriteLine("in R::operator N");
   return N(nullptr);
}

int main() {
   // Direct initialization:
   R ^r2;
   N n2(r2);   // direct initialization, calls constructor
   static_cast<N>(r2);   // also direct initialization

   R ^r3;
   // ambiguous V::operator V(R^) and R::operator V(R^)
   // static_cast<V>(r3);
}

Sortie

in N::N
in N::N

Opérateurs Convert-From

Les opérateurs de conversion créent un objet de la classe dans laquelle l’opérateur est défini à partir d’un objet d’une autre classe.

La norme C++ ne prend pas en charge les opérateurs de conversion de données ; C++ standard utilise des constructeurs à cet effet. Toutefois, lors de l’utilisation de types CLR, Visual C++ fournit une prise en charge syntactique pour l’appel d’opérateurs convert-from.

Pour interagir correctement avec d’autres langages conformes à CLS, vous souhaiterez peut-être encapsuler chaque constructeur unaire défini par l’utilisateur pour une classe donnée avec un opérateur convert-from correspondant.

Convertir à partir d’opérateurs :

  • Doit être défini en tant que fonctions statiques.

  • Peut être implicite (pour les conversions qui ne perdent pas de précision, telles que short-to-int) ou explicites, lorsqu’il peut y avoir une perte de précision.

  • Retourne un objet de la classe conteneur.

  • Doit avoir le type « from » comme seul type de paramètre.

L’exemple suivant montre un opérateur de conversion implicite et explicite « convert-from », défini par l’utilisateur (UDC).

// clr_udc_convert_from.cpp
// compile with: /clr
value struct MyDouble {
   double d;

   MyDouble(int i) {
      d = static_cast<double>(i);
      System::Console::WriteLine("in constructor");
   }

   // Wrap the constructor with a convert-from operator.
   // implicit UDC because conversion cannot lose precision
   static operator MyDouble (int i) {
      System::Console::WriteLine("in operator");
      // call the constructor
      MyDouble d(i);
      return d;
   }

   // an explicit user-defined conversion operator
   static explicit operator signed short int (MyDouble) {
      return 1;
   }
};

int main() {
   int i = 10;
   MyDouble md = i;
   System::Console::WriteLine(md.d);

   // using explicit user-defined conversion operator requires a cast
   unsigned short int j = static_cast<unsigned short int>(md);
   System::Console::WriteLine(j);
}

Sortie

in operator
in constructor
10
1

Opérateurs de conversion en opérateurs

Convertir en opérateurs convertit un objet de la classe dans laquelle l’opérateur est défini en un autre objet. L’exemple suivant montre un opérateur de conversion implicite, converti en utilisateur :

// clr_udc_convert_to.cpp
// compile with: /clr
using namespace System;
value struct MyInt {
   Int32 i;

   // convert MyInt to String^
   static operator String^ ( MyInt val ) {
      return val.i.ToString();
   }

   MyInt(int _i) : i(_i) {}
};

int main() {
   MyInt mi(10);
   String ^s = mi;
   Console::WriteLine(s);
}

Sortie

10

Un opérateur de conversion explicite défini par l’utilisateur est approprié pour les conversions susceptibles de perdre des données d’une certaine manière. Pour appeler un opérateur de conversion explicite, un cast doit être utilisé.

// clr_udc_convert_to_2.cpp
// compile with: /clr
value struct MyDouble {
   double d;
   // convert MyDouble to Int32
   static explicit operator System::Int32 ( MyDouble val ) {
      return (int)val.d;
   }
};

int main() {
   MyDouble d;
   d.d = 10.3;
   System::Console::WriteLine(d.d);
   int i = 0;
   i = static_cast<int>(d);
   System::Console::WriteLine(i);
}

Sortie

10.3
10

Pour convertir des classes génériques

Vous pouvez convertir une classe générique en T.

// clr_udc_generics.cpp
// compile with: /clr
generic<class T>
public value struct V {
   T mem;
   static operator T(V v) {
      return v.mem;
   }

   void f(T t) {
      mem = t;
   }
};

int main() {
   V<int> v;
   v.f(42);
   int i = v;
   i += v;
   System::Console::WriteLine(i == (42 * 2) );
}

Sortie

True

Un constructeur de conversion prend un type et l’utilise pour créer un objet. Un constructeur de conversion est appelé avec initialisation directe uniquement ; les casts n’appellent pas les constructeurs de conversion. Par défaut, les constructeurs de conversion sont explicites pour les types CLR.

// clr_udc_converting_constructors.cpp
// compile with: /clr
public ref struct R {
   int m;
   char c;

   R(int i) : m(i) { }
   R(char j) : c(j) { }
};

public value struct V {
   R^ ptr;
   int m;

   V(R^ r) : ptr(r) { }
   V(int i) : m(i) { }
};

int main() {
   R^ r = gcnew R(5);

   System::Console::WriteLine( V(5).m);
   System::Console::WriteLine( V(r).ptr);
}

Sortie

5
R

Dans cet exemple de code, une fonction de conversion statique implicite fait la même chose qu’un constructeur de conversion explicite.

public value struct V {
   int m;
   V(int i) : m(i) {}
   static operator V(int i) {
      V v(i*100);
      return v;
   }
};

public ref struct R {
   int m;
   R(int i) : m(i) {}
   static operator R^(int i) {
      return gcnew R(i*100);
   }
};

int main() {
   V v(13);   // explicit
   R^ r = gcnew R(12);   // explicit

   System::Console::WriteLine(v.m);
   System::Console::WriteLine(r->m);

   // explicit ctor can't be called here: not ambiguous
   v = 5;
   r = 20;

   System::Console::WriteLine(v.m);
   System::Console::WriteLine(r->m);
}

Sortie

13
12
500
2000

Voir aussi

Classes et structs