托管C++笔记(二)原创
.NET并不是平地而起的,它也是基于Win32构建的。所以不可避免的.NET会调用Win32来实现一些功能。因为标准代码的运行不受.NET运行库控制,所以在调用标准代码时,必须考虑到指针是没有被跟踪的,内存也没有垃圾回收,没有.NET上下文环境。因此不能向标准代码传递对象引用,相反,它们必须被封装为适合标准代码的形式。这个过程称为Interop.
- 非托管类不能包含托管类的数据成员
因为非托管类是直接在堆栈上创建的,所以对于托管对象是不安全的,托管对象必须处在托管堆上。
但是非托管类可以包含value类型的成员或者指向value类型的非托管指针成员,因为值类型通常是生存周期很短的小对象,它们通常在堆栈上创建。
要注意的是,值类型和C++里面的结构类似,每个成员有对齐要求,可以用StructLayout来修改对齐方式。
非托管类的方法可以使用托管类型的参数和返回值
- GCHandle可以让非托管类中包含托管指针
不要误解,这并不是说在非托管类中直接声明一个托管类型的指针,而是通过GCHandle和IntPtr的转换间接保存一个指向托管类型的指针
GCHandle是一个值类型,所以是在堆栈上构建的,同时它没有提供可用构造函数。使用方法如下:
调用GCHandle::Alloc生成一个实例用来引用一个托管对象,然后可以强制转换成IntPtr,并变换成int类型保存。
解引用则是反过来,int -> IntPtr -> GCHandle,然后便可以把GCHandle.Target转换成托管对象的指针了。
// Create instance
TestInterface^ instance = gcnew Derived();
// Create handle
GCHandle handle = GCHandle::Alloc(instance);
// Convert to pointer
IntPtr pointer = (IntPtr)handle;
// Convert back to handle from pointer
GCHandle newHandle = (GCHandle)pointer;
// Get the real pointer to nstance
if ( TestInterface::typeid->IsAssignableFrom(newHandle.Target->GetType() )
{
TestInterface^ orginInstance = (TestInterface^)newHandle.Target;
orginInstance->Name = "New Name";
}
- 托管类型不支持STL
主要是托管类型必须在托管堆上创建。但是可以新建一个托管的模板类。
范例如下:
template <class T>
ref class ArrayClass
{
public:
ArrayClass()
{
mData = gcnew array<T>(1);
}
protected:
array<T>^ mData;
};
补充:.NET2005 增加了范型的支持,参考我另外一篇随笔:托管C++中的范型和模板的区别
注意这里的array,在.NET 2005之前的版本,数组是可以用[]表示的,但是从.NET 2005开始就被替换成了cli::array了
老版本的范例:
// Old array syntax
String^ stringArray[] = __gc new String^[3];
- 全局函数
托管C++允许全局函数的存在。而其他.NET语言则要求所有函数都是类的成员函数。这个目前没有测试过,不知道是否有更新