Benutzerdefinierte Konvertierungen (C++/CLI)

In diesem Abschnitt werden benutzerdefinierte Konvertierungen (User-Defined Conversions, UDC) erläutert, wenn einer der Typen in der Konvertierung ein Verweis oder eine Instanz eines Werttyps oder Eines Bezugstyps ist.

Implizite und explizite Konvertierungen

Eine benutzerdefinierte Konvertierung kann implizit oder explizit sein. Ein UDC sollte implizit sein, wenn die Konvertierung nicht zu einem Verlust von Informationen führt. Andernfalls sollte ein expliziter UDC definiert werden.

Der Konstruktor einer systemeigenen Klasse kann verwendet werden, um einen Verweis oder Werttyp in eine systemeigene Klasse zu konvertieren.

Weitere Informationen zu Konvertierungen finden Sie unter Boxing - und Standardkonvertierungen.

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

Ausgabe

in N::N
in N::N

Convert-From-Operatoren

Convert-from-Operatoren erstellen ein Objekt der Klasse, in der der Operator aus einem Objekt einer anderen Klasse definiert ist.

Standard C++ unterstützt keine Konvertierung von Operatoren; Standard C++ verwendet zu diesem Zweck Konstruktoren. Bei Verwendung von CLR-Typen bietet Visual C++ jedoch syntaktische Unterstützung für das Aufrufen von Konvertierungsoperatoren.

Um gut mit anderen CLS-konformen Sprachen zu arbeiten, sollten Sie jeden benutzerdefinierten unären Konstruktor für eine bestimmte Klasse mit einem entsprechenden Convert-from-Operator umschließen.

Konvertieren von Operatoren:

  • Muss als statische Funktionen definiert werden.

  • Kann implizit sein (für Konvertierungen, die keine Genauigkeit verlieren, z. B. short-to-int) oder explizit, wenn möglicherweise ein Genauigkeitsverlust auftreten kann.

  • Gibt ein Objekt der enthaltenden Klasse zurück.

  • Hat den Typ "from" als alleiniger Parametertyp.

Das folgende Beispiel zeigt einen impliziten und expliziten "convert-from"-Operator (user-defined conversion, 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);
}

Ausgabe

in operator
in constructor
10
1

Convert-to-Operatoren

Convert-to-Operatoren konvertieren ein Objekt der Klasse, in der der Operator in ein anderes Objekt definiert ist. Das folgende Beispiel zeigt einen impliziten, benutzerdefinierten Konvertierungsoperator:

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

Ausgabe

10

Ein expliziter benutzerdefinierter Konvertierungsoperator eignet sich für Konvertierungen, die potenziell Daten verlieren. Um einen expliziten Konvertierungsoperator aufzurufen, muss eine Umwandlung verwendet werden.

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

Ausgabe

10.3
10

So konvertieren Sie generische Klassen

Sie können eine generische Klasse in T konvertieren.

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

Ausgabe

True

Ein Konvertierungskonstruktor verwendet einen Typ und verwendet ihn zum Erstellen eines Objekts. Ein Konvertierungskonstruktor wird nur mit direkter Initialisierung aufgerufen. Umwandlungen rufen keine Konvertierungskonstruktoren auf. Standardmäßig sind konvertierungskonstruktoren für CLR-Typen explizit.

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

Ausgabe

5
R

In diesem Codebeispiel führt eine implizite statische Konvertierungsfunktion dieselbe Funktion wie ein expliziter Konvertierungskonstruktor aus.

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

Ausgabe

13
12
500
2000

Siehe auch

Klassen und Strukturen