网学网为广大网友收集整理了,C++/CLI解析之基于堆栈的对象与跟踪引用,希望对大家有所帮助!
Point p1, p2(3,4); |
N n1; N& n2 = n1; |
Point% p3 = p2; |
Point^ hp = gcnew Point(2,5); Point% p4 = *hp; Point% p5 = *gcnew Point(2,5); |
在此,hp是一个Point的句柄,而p4是此句柄的别名。虽然句柄不是一个指针,但也能使用一元 * 操作符来对句柄解引用。(在C++/CLI标准制定期间,是否就引入一元 ^ 操作符来取代 * 还进行过一场讨论,反方观点是,在编写模板时,* 对句柄或指针进行解引用有非常高的价值。)当然,即使hp有了一个新值,p4在此仍是同一Point的别名。另外要说明一点,当对象有一个句柄或跟踪引用时,就不能被垃圾回收器回收了。
再来看p5,对gcnew返回的句柄进行了解引用,虽然差不多每个引用类类型的句柄,都能被解引用,但有两种类型的句柄却不能被解引用,这两种类型是:System::String与array<T>。
取句柄操作符
如果想把p1的值写到标准输出,代码似乎应该像下面这样:
Console::WriteLine("p1 is {0}", p1); |
Point p6(3,4), p7 = p6; |
Point(Point% p) { X = p.X; Y = p.Y; } |
N(const N& n); |
p7 = p6; |
Point% operator=(Point% p) { X = p.X; Y = p.Y; return *this; } |
相等性操作符
通过为Point定义一个拷贝构造函数和一个赋值操作符,就可以处理那些数值类型的实例了,你可以初始化它们、把它们传给函数、或把它们从函数中返回;但实际上,可能还再需要一个操作符--相等性比较操作符,它能像如下定义:
static bool operator==(Point% p1, Point% p2) { if (p1.GetType() == p2.GetType()) { return (p1.X == p2.X) && (p1.Y == p2.Y); } return false; } |
由于一个跟踪引用不可能为数值nullptr,所以就不必对此值进行检查了,又由于p1与p2是两个Point的别名,所以可使用点操作符调用GetType和属性X与Y的get程序。
能同时满足两方面需求吗?
以前说过,对一个引用类而言,相等性的判别是通过一个Equals函数而不是重载 == 操作符来实现的,并且重载了一个接受句柄的 == 操作符,指出了使用上的问题。那让我们再来回顾一下这个话题。
当在C++/CLI中设计并实现一个引用类时,就要想到"这个类的使用者,会使用C++/CLI语言进行编程,还是会使用如C#、J#、VB.NET之类的其他语言呢,或者两者都使用呢?"
C++程序员习惯于把类实例当作数值来对待,所以,他们期待类中有一个拷贝构造函数及一个赋值操作符,且对某些类来说,还会期待实现相等或不相等操作符;另一方面,C#、J#、VB.NET程序员只能通过句柄来操纵类实例,所以他们只想要克隆或Equals函数,至于拷贝构造函数与赋值操作符,他们无须知道,也无须关心。
即便C++程序员更倾向于使用 == 操作符,但一个带有Equals函数的引用类可被任意语言所调用,所以在设计引用类时应尽量实现此函数,不过话说回来,如果对一个不包含Equals函数的类实例调用此函数,将会产生无法预料的后果。
如果在一个引用类中,提供了可接受两个跟踪引用的 == 操作符函数,一般上也可满足C++/CLI程序员的需要。虽然也能提供一个接受两个句柄的 == 操作符函数,但似乎不可能被这两组程序员使用。
简而言之,既可为C++/CLI程序员,也可为其他.NET语言程序员、或同时为两者实现一个引用类,那么,是不是可把它们简单地分为C++/CLI与"其他语言"两个阵营呢,但事情似乎总不是这么简单的,举例来说,虽然System::String是一个引用类,它提供了可接受两个句柄的 == 操作符与 != 操作符函数,但是,比较的是字符串的值,而不是它们的句柄。一般来说,在引用类中使用值这个说法,是有点让人感觉怪怪的,但对一个string类来说,却又是合情合理的。
在此非常清楚的一点是,万能的方法是不存在的。为对引用类的使用者,提供最适当的接口,就必须在基于他们所使用语言的基础上,多考虑一下他们的期望。但无论如何,C++/CLI程序员想要使用其他语言创建的引用类,就不得不要适应没有拷贝构造函数与赋值操作符这些情况。
其他话题
以下的话题非常简短、但却十分有帮助:
1、前面也提到,const不是很适合CLI,且在引用类中,C++/CLI也不允许用const(或volatile)来限定成员函数;但个关键字可用在某些类中实例构造函数或成员函数上。那么在此情况下,它的类型到底是什么呢?对本地类型N来说,它是N* const;然而,对一个引用类R来说,它只是一个R^。虽然句柄不是const限定的,但它的值却不能被修改。
2、Point::ToString的实现使用了如下形式:
return String::Concat("(", X, ",", Y, ")"); |
return String::Format("({0},{1})", X, Y); |
Decimal x = Decimal::Parse("23.00"); Decimal y = Decimal::Parse("2.000"); Decimal result = x * y + Decimal::Parse("2.5"); Console::WriteLine(result); |
literal double PI = 3.1415926; literal int MinValue = -10, MaxValue = 10; literal int Range = MaxValue - MinValue + 1; enum Direction {North, South, East, West}; literal Direction Home = North; literal System::String^ Title = "Annual Report"; |