装箱(C++ 组件扩展)
Visual C++ 编译器可以在称为装箱的进程中将值类型转换为对象,并在称为取消装箱的进程中将对象转换成值类型。
所有运行时
(无适用于所有运行时的语言功能的备注。)
Windows Runtime — Windows 运行时
C++/CX 支持装箱值类型和取消装箱引用类型的简短语法。 值类型在分配给类型变量 Object 时装箱。 如果 Object 变量分配给值类型变量时,该变量不装箱,且不装箱的类型用括号指定;也就是说,对象变量转换为值类型。
Platform::Object^ object_variable = value_variable;
value_variable = (value_type) object_variable;
要求
编译器选项:/ZW
示例
以下代码示例为装箱和取消装箱 DateTime 值。 首先,该示例获取表示当前日期和时间的 DateTime 值,然后将其分配给 DateTime 变量。 然后,通过将 DateTime 分配到对象变量,对其进行装箱。 最后,通过将装箱值分配到另一个 DateTime 变量来取消装箱。
要测试示例,请创建 BlankApplication 项目,替换 BlankPage::OnNavigatedTo() 方法,然后在后括号处指定断点并对变量 str1 赋值。 当示例达到后括号时,检查 str1。
void BlankPage::OnNavigatedTo(NavigationEventArgs^ e)
{
using namespace Windows::Globalization::DateTimeFormatting;
Windows::Foundation::DateTime dt, dtAnother;
Platform::Object^ obj1;
Windows::Globalization::Calendar^ c =
ref new Windows::Globalization::Calendar;
c->SetToNow();
dt = c->GetDateTime();
auto dtf = ref new DateTimeFormatter(
YearFormat::Full,
MonthFormat::Numeric,
DayFormat::Default,
DayOfWeekFormat::None);
String^ str1 = dtf->Format(dt);
OutputDebugString(str1->Data());
OutputDebugString(L"\r\n");
// Box the value type and assign to a reference type.
obj1 = dt;
// Unbox the reference type and assign to a value type.
dtAnother = (Windows::Foundation::DateTime) obj1;
// Format the DateTime for display.
String^ str2 = dtf->Format(dtAnother);
OutputDebugString(str2->Data());
}
有关更多信息,请参见https://msdn.microsoft.com/library/windows/apps/hh969554.aspx。
公共语言运行时
Visual C++ 编译器现将值类型装箱到 Object。这可能是因为存在编译器定义的转换以将值类型转换为 Object。
装箱和取消装箱能够使值类型作为对象进行处理。 值类型(包括结构类型和内置类型,如 int)与 Object 类型可相互转换。
有关详细信息,请参阅:
要求
编译器选项:/clr
示例
示例
以下示例说明了隐式装箱的工作方式。
// vcmcppv2_explicit_boxing2.cpp
// compile with: /clr
using namespace System;
ref class A {
public:
void func(System::Object^ o){Console::WriteLine("in A");}
};
value class V {};
interface struct IFace {
void func();
};
value class V1 : public IFace {
public:
virtual void func() {
Console::WriteLine("Interface function");
}
};
value struct V2 {
// conversion operator to System::Object
static operator System::Object^(V2 v2) {
Console::WriteLine("operator System::Object^");
return (V2^)v2;
}
};
void func1(System::Object^){Console::WriteLine("in void func1(System::Object^)");}
void func1(V2^){Console::WriteLine("in func1(V2^)");}
void func2(System::ValueType^){Console::WriteLine("in func2(System::ValueType^)");}
void func2(System::Object^){Console::WriteLine("in func2(System::Object^)");}
int main() {
// example 1 simple implicit boxing
Int32^ bi = 1;
Console::WriteLine(bi);
// example 2 calling a member with implicit boxing
Int32 n = 10;
Console::WriteLine("xx = {0}", n.ToString());
// example 3 implicit boxing for function calls
A^ a = gcnew A;
a->func(n);
// example 4 implicit boxing for WriteLine function call
V v;
Console::WriteLine("Class {0} passed using implicit boxing", v);
Console::WriteLine("Class {0} passed with forced boxing", (V^)(v)); // force boxing
// example 5 casting to a base with implicit boxing
V1 v1;
IFace ^ iface = v1;
iface->func();
// example 6 user-defined conversion preferred over implicit boxing for function-call parameter matching
V2 v2;
func1(v2); // user defined conversion from V2 to System::Object preferred over implicit boxing
// Will call void func1(System::Object^);
func2(v2); // OK: Calls "static V2::operator System::Object^(V2 v2)"
func2((V2^)v2); // Using explicit boxing: calls func2(System::ValueType^)
}
Output
1