实例解析C++/CLI之值类型
实例,只代表两个Point有相同的坐标,但修改其中一者的x坐标,不会影响到另一者的相同值。
当一个Point的实例传递到Equals时,作为值类型(其最终也都继承自System::Object)而言,装箱就发生了--也就是说,在垃圾回收堆上分配了一个Object的实例,而其包含了传递进来Point的一份副本。因为是创建了一个新的对象,所以只有一个句柄,也不会有相同的其他Point。 之前接受Point句柄的 == 操作符函数,现在已经精简到一行,并且由接受句柄改为接受Point值,且用于选择成员的指向操作符 -> 也被替换为点操作符。因为给定的值类型为sealed,所以与值类型参数Point唯一匹配的则为同类型的值了。同样地,既无需检查nullptr来确认是否为自身比较,也无需检查传递进来的对象是否类型完全一致。 而之前用于追踪引用的 == 操作符函数基本上无需太多改动,但删除了检测同一类型这一部分。然而,这两个== 操作符函数,最好只保留一个,以免在point1 == point2调用时引发歧义。(在声明函数参数时,也可使用标准C++引用符&,而不是%,因为两者可在本地类型与值类型之间互换。但由于这种类型的实例不存在于垃圾回收堆中,所以在垃圾回收期间不会改变它们的位置,因此也不需要对它们的位置进行追踪。) 例2使用了值类中的大多数成员,最主要的是它包含了静态Point类的实例,而这在引用类中是不可能完成的。事实上,不只是不能有一个引用类的静态实例,甚至也不能有一个此类型的静态句柄。 例2: using namespace System;
在第一次调用Console::WriteLine时,用传值的方式传递进一个Point,但是,这个函数却指望着接受一个对象引用,在此,Point值被自动装箱,并把装箱后的对象引用传递给函数。 在定义中可看到,p5是由默认的拷贝构造函数初始化,而接下来的一行代码,默认的赋值操作符把p2逐位复制给p5。 引用类与值类的差异 如果我们在上述的Point引用类中加入一个ID号,用于跟踪每个不同的Point引用对象,且再添加一个布尔类型的TraceID用于指明是否进行跟踪;那么,把它改为值类之后,会有什么不同呢? 再次提醒,是不能为一个值类定义默认构造函数、拷贝构造函数及赋值操作符的,但不幸的是,这些都是我们ID解决方案中所需用到的。在引用类版本的默认构造函数中,会将X与Y两个坐标值、ID值都设置为零,并取得下一个ID赋给ID实例字段;反观值类实现的版本,对以此方式构建的每个新Point,都是由默认为零值的ID构成,但是,我们却想每个ID值为唯一。 另一个类似问题也是由缺少显式的拷贝构造函数造成的,在我们想要一个全新的对象时,值类的逐位复制却造成新对象的ID与被拷贝对象的ID一样。 另外,在赋值时,如果我们只设置即有Point的值,那么Point的ID不应改变,也就是说,虽然任一或两个坐标都可能改变,但它仍是同一Point对象,然而,逐位复制却导致目标Point的ID被源对象ID覆盖。 虽然此处没有列出包含ID的Point类,但例3中的程序显示了引用类与值类的差异所在。 例3: using namespace System; |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |