Conversioni definite dall'utente (C++/CLI)
Questa sezione illustra le conversioni definite dall'utente (UDC) quando uno dei tipi nella conversione è un riferimento o un'istanza di un tipo valore o di un tipo riferimento.
Conversioni implicite ed esplicite
Una conversione definita dall'utente può essere implicita o esplicita. Un UDC deve essere implicito se la conversione non comporta una perdita di informazioni. In caso contrario, è necessario definire un UDC esplicito.
Il costruttore di una classe nativa può essere usato per convertire un tipo riferimento o valore in una classe nativa.
Per altre informazioni sulle conversioni, vedere Conversione boxing e 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);
}
Output
in N::N
in N::N
Operatori di tipo converti da
Gli operatori Convert-from creano un oggetto della classe in cui l'operatore viene definito da un oggetto di un'altra classe.
C++ standard non supporta gli operatori convert-from; Lo standard C++ usa costruttori a questo scopo. Tuttavia, quando si usano tipi CLR, Visual C++ fornisce supporto sintattico per chiamare gli operatori convert-from.
Per interagire bene con altri linguaggi conformi a CLS, è possibile eseguire il wrapping di ogni costruttore unario definito dall'utente per una determinata classe con un operatore convert-from corrispondente.
Operatori Convert-from:
Deve essere definito come funzioni statiche.
Può essere implicito (per le conversioni che non perdono precisione, ad esempio short-to-int) o esplicite, quando può verificarsi una perdita di precisione.
Restituisce un oggetto della classe contenitore.
Il tipo "from" deve essere l'unico tipo di parametro.
L'esempio seguente mostra un operatore di conversione implicito ed esplicito "convert-from", definito dall'utente (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);
}
Output
in operator
in constructor
10
1
Operatori di conversione in
Gli operatori Convert-to convertono un oggetto della classe in cui l'operatore viene definito in un altro oggetto. L'esempio seguente mostra un operatore di conversione implicito, convert-to, definito dall'utente:
// 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);
}
Output
10
Un operatore di conversione da conversione definito dall'utente esplicito è appropriato per le conversioni che potenzialmente perdono dati in qualche modo. Per richiamare un operatore convert-to esplicito, è necessario usare un cast.
// 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);
}
Output
10.3
10
Per convertire classi generiche
È possibile convertire una classe generica in 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) );
}
Output
True
Un costruttore di conversione accetta un tipo e lo usa per creare un oggetto. Un costruttore di conversione viene chiamato solo con inizializzazione diretta; I cast non richiamano costruttori di conversione. Per impostazione predefinita, i costruttori di conversione sono espliciti per i tipi 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);
}
Output
5
R
In questo esempio di codice, una funzione di conversione statica implicita esegue la stessa operazione di un costruttore di conversione esplicito.
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);
}
Output
13
12
500
2000