Konwersje zdefiniowane przez użytkownika (C++/CLI)

W tej sekcji omówiono konwersje zdefiniowane przez użytkownika (UDC), gdy jeden z typów konwersji jest odwołaniem lub wystąpieniem typu wartości lub typu odwołania.

Niejawne i jawne konwersje

Konwersja zdefiniowana przez użytkownika może być niejawna lub jawna. Funkcja UDC powinna być niejawna, jeśli konwersja nie spowoduje utraty informacji. W przeciwnym razie należy zdefiniować jawną funkcję UDC.

Konstruktor klasy natywnej może służyć do konwertowania typu odwołania lub wartości na klasę natywną.

Aby uzyskać więcej informacji na temat konwersji, zobacz Boxing and Standard Conversions (Konwersje w warstwie Standardowa).

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

Wyjście

in N::N
in N::N

Konwersja z operatorów

Operatory konwertuj-from tworzą obiekt klasy, w której operator jest definiowany z obiektu innej klasy.

Język C++ w warstwie Standardowa nie obsługuje operatorów konwertuj-from; Standard C++ używa w tym celu konstruktorów. Jednak w przypadku używania typów CLR program Visual C++ zapewnia obsługę składni dla wywoływania operatorów convert-from.

Aby dobrze współdziałać z innymi językami zgodnymi ze specyfikacją CLS, możesz chcieć opakować każdy jednoargumentowy konstruktor zdefiniowany przez użytkownika dla danej klasy z odpowiednim operatorem konwertuj-from.

Konwertuj z operatorów:

  • Określa się je jako funkcje statyczne.

  • Może być niejawny (w przypadku konwersji, które nie tracą precyzji, takiej jak short-to-int) lub jawne, gdy może dojść do utraty precyzji.

  • Zwraca obiekt zawierającej klasę.

  • Musi mieć typ "from" jako jedyny typ parametru.

Poniższy przykład przedstawia niejawny i jawny operator "convert-from", zdefiniowany przez użytkownika (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);
}

Wyjście

in operator
in constructor
10
1

Konwertowanie na operatory

Konwertuj na operatory konwertują obiekt klasy, w której operator jest zdefiniowany do innego obiektu. W poniższym przykładzie przedstawiono niejawny, zdefiniowany przez użytkownika operator konwersji konwertujące na użytkownika:

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

Wyjście

10

Jawnie zdefiniowany przez użytkownika operator konwersji na konwersję jest odpowiedni dla konwersji, które potencjalnie tracą dane w jakiś sposób. Aby wywołać jawny operator konwertuj-do, należy użyć rzutowania.

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

Wyjście

10.3
10

Aby przekonwertować klasy ogólne

Klasę ogólną można przekonwertować na 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) );
}

Wyjście

True

Konstruktor konwertujący przyjmuje typ i używa go do utworzenia obiektu. Konstruktor konwertujący jest wywoływany tylko z bezpośrednim inicjowaniem; rzutowania nie będą wywoływać konwertowania konstruktorów. Domyślnie konwertowanie konstruktorów jest jawne dla typów 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);
}

Wyjście

5
R

W tym przykładzie kodu niejawna funkcja konwersji statycznej wykonuje to samo, co jawny konstruktor konwersji.

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

Wynik

13
12
500
2000

Zobacz też

Klasy i struktury