C++/CLI中的const literal initonly 友元
Visual C++并不允许在const对象上调用成员函数,除非该成员函数也被声明为const。
C++/CLI托管代码中,无法把任何类型的函数声明为const;但可以把一个对象声明为const;然而由于无法编写const函数,这种const对象也几乎没有办法进行操作。
我们可以在句柄和函数实参中使用const;就像对指针使用const一样当;我们把一个引用传递给一个函数但有希望限制对这个引用所指向的数据进行修改时,这种做法很实用。
托管数组不支持const限定符,即无法在C++/CLI中使用const声明或传递托管数组。
本地C++中的静态常量成员在C++/CLI中应该只使用关键字literal声明。被声明为literal的数据成员必须在声明的时候进行初始化。literal必须是类的数据成员而不能是全局静态变量。
C++/CLI使用inionly把一个成员变量声明为initonly指定了这个成员只能在类的构造函数中被赋值,但并不意味着它不可以被重新赋值,只是他无法在构造函数之外被赋值或重新赋值。
C++/CLI托管类无法声明友元类或友元函数;本地类可以把托管类声明为它的友元。
堆栈语义
当我们在不使用new的情况下创建一个本地对象时,Visual C++把这种对象(自动变量)存储在堆栈而不是本地堆中,堆栈内存是由C++运行时自动管理的。当自动变量离开作用域时,它的析构函数会被隐式的调用,它所占据的内存会被自动收回,不需要程序员显示的调用delete。这种风格的声明称为堆栈语义。
C++/CLI并不允许我们对3种特定的托管类型使用堆栈语义:String对象,托管数组和委托。这些类型的对象必须被定义为各自类型的句柄。任何其它C++/CLI类型以及任何自定义类型都可以使用堆栈语义来声明。
托管代码中的指针
interior_ptr<type>
是native pointer的超集,native pointer能做的,Interior pointer也一样能做。当垃圾回收器移动对象时,Interior pointer能随之移动,并始终指向该对象。
------《Pro Visual C++_CLI and the .NET 2.0 Platform》p815
Interior_ptr可以指向引用句柄、值类型、装箱类型句柄、托管类成员、托管数组的元素。不能指向引用类型本身。
*ip 是ip所值的类型type的值
&ip 是ip指向托管堆中的地址
pin_ptr<type>
在外部调用托管堆中指针时,垃圾回收过程中该指针会发生改变,引起外部调用的错误。必须使用pin_ptr指针将该指针固定。
pinned pointer可以指向引用句柄、值类型、托管数组的元素。不能指向引用类型,但能指向引用类型的成员(不支持钉住由 new 表达式返回的整个对象。相反,需要钉住内部成员的地址。--MSDN)。可以完成native pointer的所有的功能,如指针比较和指针运算。
都不能由跟踪句柄直接赋值。而是必须由&操作符取地址。因为interior_ptr pin_ptr是独立的类,只能由地址赋值,而不能由托管类型赋值。
int^ m_int = gcnew int(100);
interior_ptr<int> ipint = &*m_int; //ok
interior_ptr<int> ipint = m_int; //error
Value class Vtest{}Ref class Rtest{}Vtest ^vtest = gcnew Vtest; //值类型对象pin_ptr< Vtest > pinp;pinp = vtest; //errorpinp = &* vtest; //okinterior_ptr< Vtest > ip;ip = &* vtest; //okpin_ptr< Vtest ^> pinhundle;pinhundle = vtest; //errorpinhundle = & vtest; //okinterior_ptr< Vtest ^> iphundle;iphundle = & vtest; //okRTest ^rtest = gcnew RTest; //引用类型对象pin_ptr< Rtest > pinp; //error , 不可以钉住引用类型对象interior_ptr < Rtest > pinp; //error , 不可以指向引用类型对象ref class G {public: void incr(int* pi) { *pi += 1; }};ref struct H { int j; };void f( G^ g ) { H ^ph = gcnew H; Console::WriteLine(ph->j); pin_ptr<int> pj = &ph->j; //ok,可以钉住引用类型对象的成员 g->incr( pj ); Console::WriteLine(ph->j);}
Pin_ptr指针使用例子
value class Test {public: int i; };#pragma unmanagedvoid incr (int *i){ (*i) += 10;}#pragma managedvoid main () { Test ^test = gcnew Test(); interior_ptr<int> ip = &test->i; (*ip) = 5;// incr( ip ); // invalid pin_ptr<int> i = ip; // i is a pinned int pointer incr( i ); // pinned pointer to interior pointer passed to a // native function call expecting a native pointer Console::WriteLine ( test->i );}
非托管代码中的函数void incr(int *i)需要int指针,不能将interior_ptr<int>的ip传递给该函数。因为内部指针会随着垃圾回收改变地址,而将其转换为pin_ptr<int>,就是将地址固定,以供外部函数incr(int* i)调用该指针。
和*指针的转换
正因为pin_ptr<>所指向的地址是固定的,因此才能和*指针转换。而interior_ptr<>无此性质。
pin_ptr<ClassValue> pValue = &value;; ClassValue* p = pValue; //ok
interior_ptr就不可以和*指针转换。
interior_ptr<ClassValue> pValue = &value;; ClassValue* p = pValue; //error
值类型的指针
在新语法中,值类型指针分为两种类型:V*(限于非 CLR 堆位置)和内部指针 interior_ptr<V>(允许但不要求托管堆内的地址)。
// may not address within managed heap
V *pv = 0;
// may or may not address within managed heap
interior_ptr<V> pvgc = nullptr;
托管扩展中的下列声明全部映射到新语法中的内部指针。(它们是 System命名空间内的值类型。)
Int32 *pi; // => interior_ptr<Int32> pi;
Boolean *pb; // => interior_ptr<Boolean> pb;
E *pe; // => interior_ptr<E> pe; // Enumeration
内置类型不被认为是托管类型,尽管它们确实在System命名空间内作为类型的别名。
---------------------
Reference:C++/CLI 实战技术收集