Conversiones definidas por el usuario (C++/CLI)
En esta sección se describen las conversiones definidas por el usuario (UDC) cuando uno de los tipos de la conversión es una referencia o instancia de un tipo de valor o un tipo de referencia.
Conversiones implícitas y explícitas
Las conversiones definidas por el usuario pueden ser implícitas o explícitas. Una UDC debe ser implícita si no da lugar a una pérdida de información. De lo contrario, se debe definir una UDC explícita.
El constructor de una clase nativa se puede usar para convertir un tipo de referencia o de valor en una clase nativa.
Para más información sobre las conversiones, consulte Conversión boxing y Conversiones estándar.
// 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);
}
Salida
in N::N
in N::N
Operadores de Convertir desde
Los operadores convert-from crean un objeto de la clase en la que el operador se define a partir de un objeto de alguna otra clase.
C++ estándar no admite operadores convert-from; C++ estándar usa constructores para este fin. Sin embargo, al usar tipos de CLR, Visual C++ proporciona compatibilidad sintáctica para operadores convert-from de llamada.
Para interoperar bien con otros lenguajes conformes a CLS, puede que desee encapsular cada constructor unario definido por el usuario para una clase determinada con un operador convert-from correspondiente.
Operadores convert-from:
Se definirán como funciones estáticas.
Pueden ser implícitas (para conversiones que no pierden precisión, como short-to-int) o explícitas, cuando puede haber una pérdida de precisión.
Devolverá un objeto de la clase contenedora.
Tendrá el tipo "from" como el único tipo de parámetro.
En el ejemplo siguiente se muestra un operador de conversión implícito y explícito "convert-from", definido por el usuario (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);
}
Salida
in operator
in constructor
10
1
Operadores convert-to
Los operadores convert-to convierten un objeto de la clase en la que el operador se define en algún otro objeto. En el ejemplo siguiente se muestra un operador implícito convert-to definido por el usuario:
// 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);
}
Salida
10
Un operador de conversión convert-to explícito definido por el usuario es adecuado para las conversiones que podrían perder datos de alguna manera. Para invocar un operador convert-to explícito, se debe usar una conversión.
// 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);
}
Salida
10.3
10
Para convertir clases genéricas
Puede convertir una clase genérica 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) );
}
Salida
True
Los constructores de conversión toman un tipo y lo usan para crear un objeto. Solo se llama a los constructores de conversión con inicialización directa; las conversiones no invocarán constructores de conversión. De forma predeterminada, los constructores de conversión son explícitos para los tipos de 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);
}
Salida
5
R
En este ejemplo de código, una función de conversión estática implícita realiza la misma función que un constructor de conversión explícito.
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);
}
Salida
13
12
500
2000