值类型 VS 引用类型 (C++/CLI)
值类型自动继承自 System::ValueType, 引用类型自动继承自 System::Object,
虽然S ystem::ValueType 也继承自 System::Object, 但二者仍有不少差别。
1. 值类型分配在栈上,引用类型分配在托管堆上。
2. 值类型不能作为另一个类型的基类,但可以实现接口。
3. 值类型不可以定义析构器,也不可以定义终结器。所以不要在值类型里面引用
非托管资源,不要为值类型实现 Dispose 模式。
4. 值类型默认实现拷贝构造函数与赋值重载操作符,引用类型默认不实现拷贝构
造函数与赋值重载操作符,这个设计使得使用栈对象时非常不方便。
5. 值类型不可以自定义无参构造函数,拷贝构造函数及赋值重载操作符,只能使
用默认的(拷贝及赋值内部是以逐位复制的形式实现的)。
6. 对于值类型来说,可以定义为全局变量,也可以定义为全局静态实例,引用类型却
不可以这么做。值类型和引用类型都不能定义为全局追踪句柄及全局静态追踪
句柄。二者都可以定义为静态实例字段和静态追踪句柄字段。
7. 值类型可以包含另一个值类型,可以包含在一个引用类型中,可以包含
一个引用类型的追踪句柄,但不可以直接包含一个引用类型,下面的代
码不能通过编译:
value class MyRefClass
{
public:
Object Data;
};
而要改成下面的形式:
value class MyRefClass
{
public:
Object^ Data;
};
8. 值类型和引用类型都不能包含本地类型(包括本地C++ 数组及本地类,本地结构等),
而应该使用本地指针。
9. 和引用类型一样,值类型不能包含在自身类型中。但可以包含自身类型的
追踪句柄。下面的代码不能通过编译:
value class Node
{
public:
Node Next;
};
改为下面的形式可以通过编译:
value class Node
{
public:
Node^ Next;
};
10.引用类型的实例构造函数或成员函数中,this 为追踪句柄,值类型中则为
内部指针。
11.值类型的追踪句柄不可以作为泛型的 typename, 而只能使用值类型本身,
下面的代码不能通过编译:
using namespace System::Collections::Generic;
value class Data
{
};
int main() {
List<Data^>^ list = gcnew List<Data^>();
return 0;
}
引用类型不可直接作为泛型的 typename, 而只能使用追踪句柄,下面的
代码不能通过编译:
using namespace System::Collections::Generic;
ref class Data
{
};
int main() {
List<Data>^ list = gcnew List<Data>();
return 0;
}
如果需要将一个值类型的追踪句柄放在一个集合内,只能对其装箱,可以这样
做:
using namespace System::Collections;
value class Data
{
};
int main() {
ArrayList^ list = gcnew ArrayList();
Data^ data = gcnew Data();
list->Add(data);
return 0;
}
或者这样做:
using namespace System;
using namespace System::Collections::Generic;
value class Data
{
};
int main() {
List<Object^>^ list = gcnew List<Object^>();
Data^ data = gcnew Data();
list->Add(data);
return 0;
}
值得注意的是,这里的装箱是强类型装箱,即C++/CLI 里常被提及的
"强类型装箱实例",请参见我的另一篇博客 —— 让.Net 值类型具有引用
传递的行为。