设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 3665|回复: 21
打印 上一主题 下一主题

[已经解决] 关于Viewport的诡异测试

 关闭 [复制链接]
头像被屏蔽

Lv1.梦旅人 (禁止发言)

梦石
0
星屑
46
在线时间
10 小时
注册时间
2007-5-27
帖子
2558

第1届Title华丽大赛新人奖

跳转到指定楼层
1
发表于 2009-9-15 20:07:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
提示: 作者被禁止或删除 内容自动屏蔽

Lv1.梦旅人

梦石
0
星屑
61
在线时间
24 小时
注册时间
2008-8-5
帖子
1924
2
发表于 2009-9-15 23:10:42 | 只看该作者
clone 的调用是成功了的,克隆后的对象 id 也不同,只不过通过克隆体调用 set 或者 width= 的时候引用的是本体的变量,而调用本体的 width= 就冇问题了:
  1. v = Viewport.new(0,0,12,12)

  2. a = v.rect
  3. b = a.clone
  4. c = b.clone

  5. a.width = 9999

  6. p a, b, c
复制代码
可见至少 width 和 height 方法确实返回的是正确克隆后的宽度和高度变量
这个应该还是和 Rect 的属性在 C 中实现有关,因为 Rect 本身没有覆盖 Object 的 clone 方法,而 Sprite啊、Viewport啊之类的都覆盖了的,所以下面 p 出来是 false 的类都应该有这个问题:
  1. p "Rect #{Rect.instance_methods(false).include?("clone")}",
  2.   "Sprite #{Sprite.instance_methods(false).include?("clone")}",
  3.   "Bitmap #{Bitmap.instance_methods(false).include?("clone")}",
  4.   "Viewport #{Viewport.instance_methods(false).include?("clone")}",
  5.   "Plane #{Plane.instance_methods(false).include?("clone")}",
  6.   "Color #{Color.instance_methods(false).include?("clone")}",
  7.   "Font #{Font.instance_methods(false).include?("clone")}",
  8.   "Window #{Window.instance_methods(false).include?("clone")}",
  9.   "Tilemap #{Tilemap.instance_methods(false).include?("clone")}",
  10.   "Tone #{Tone.instance_methods(false).include?("clone")}",
  11.   "Table #{Table.instance_methods(false).include?("clone")}"
复制代码
回复 支持 反对

使用道具 举报

头像被屏蔽

Lv1.梦旅人 (禁止发言)

梦石
0
星屑
46
在线时间
10 小时
注册时间
2007-5-27
帖子
2558

第1届Title华丽大赛新人奖

3
 楼主| 发表于 2009-9-16 21:32:28 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
61
在线时间
24 小时
注册时间
2008-8-5
帖子
1924
4
发表于 2009-9-16 23:04:27 | 只看该作者
哦,原来覆盖是为了禁止 clone,还真不知道~

……不能 Marshal 确实诡异,无源码无从分析
不过我发现只要不是在 RGSS 类内部(比如 Viewport 的构造函数)分配的某个属性对象,至少 clone 可以正常工作了:
  1. a = Rect.new(0, 0, 12, 12)
  2. v = Viewport.new(0, 0, 1, 1)
  3. v.rect = a

  4. b = v.rect.clone
  5. b.width = 999

  6. p a, b
复制代码
另外不仅仅是 rect,只要是这些 RGSS 类的对象属性都有这个问题:
  1. s = Sprite.new

  2. a = s.color
  3. b = a.clone

  4. b.red = 88

  5. p a, b
复制代码
  1. p = Plane.new
  2. a = p.color

  3. b = a.clone
  4. b.red = 999

  5. p a, b
复制代码
对象 id 不同,说明在 Ruby 层的克隆成功了,只不过如果这个对象是在 C 层上分配的话,推测就是没有克隆数据,而是克隆了指针(?!)
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
128 小时
注册时间
2009-1-28
帖子
2790
5
发表于 2009-9-18 17:46:50 | 只看该作者
好东西,俺来膜拜下

炼金术的根本法则是等价交换。想要获得,必须失去同等价值的东西。每当烦躁的时候,煎熬在不想做却又正在做的烦心事中的时候,我就安慰自己,提醒自己做这些事情的目的所在,告诉自己不要忽略所获得或者即将获得的回报,物质的,精神的,肉体的,灵魂的回报!只做想做的事情,就会失去不想失去的东西。
回复 支持 反对

使用道具 举报

Lv3.寻梦者

孤独守望

梦石
0
星屑
3137
在线时间
1535 小时
注册时间
2006-10-16
帖子
4321

开拓者贵宾

6
发表于 2009-9-18 17:53:32 | 只看该作者
如果我这么说阁下觉得可以理解吗
  1. def rect
  2. return Rect.new(x,y,width,height) # 伪代码,实际公式要比这个复杂= =
  3. end
  4. def rect=(value)
  5. # 同
  6. end
复制代码
这个方法只是为了方便使用而已……临时对象……结果自然可想而知
菩提本非树,明镜本非台。回头自望路漫漫。不求姻缘,但求再见。
本来无一物,何处惹尘埃。风打浪吹雨不来。荒庭遍野,扶摇难接。
不知道多久更新一次的博客
回复 支持 反对

使用道具 举报

Lv1.梦旅人

风之塞尔达

梦石
0
星屑
50
在线时间
57 小时
注册时间
2005-10-22
帖子
2492

贵宾

7
发表于 2009-9-18 19:36:13 | 只看该作者
.clone方法返回的的确是Viewport.rect的属性的拷贝,
但是clone方法返回的是一个"冻结的,且会感染原实例"的实例(我英文不好-  -!!)...
也就是clone产生的实例被修改了,会影响到原实例. 但是源实例被修改了,则clone产生的实例不会受到影响

  1. a = Viewport.new(0,0,12,12)
  2. b = a.rect.clone
  3. a.rect.width = 24
  4. p a.rect, b, "ID:", a.rect.object_id, b.object_id, "Ins:", a.rect.inspect, b.inspect
  5. b.width = 48
  6. p a.rect, b, "ID:", a.rect.object_id, b.object_id, "Ins:", a.rect.inspect, b.inspect

  7. c = a.rect.clone
  8. a.rect.width = 12
  9. p a.rect, c, "ID:", c.object_id, "Ins:", c.inspect
  10. c.width = 48
  11. p a.rect, c, "ID:", c.object_id, "Ins:", c.inspect
  12. exit
复制代码
还有 Viewprot不能被clone,并不一定要重载clone方法
如果Viewport定义的ruby类具有const属性, 那么根据const的原则,是不可以存在一个可以感染它的clone实例,也就是Viewport不能被clone的原因

  1. VALUE
  2. rb_obj_clone(obj)
  3.     VALUE obj;
  4. {
  5.     VALUE clone;

  6.     if (rb_special_const_p(obj)) {
  7.         rb_raise(rb_eTypeError, "can't clone %s", rb_obj_classname(obj));
  8.     }
  9.    ... ...
  10.    ... ...
  11.     return clone;
  12. }
复制代码
以上只是个人理解...  实际还要去看源代码- -
在程序里延续塞尔达的传说, 在画板上勾勒塞尔达的轮廓!!
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
61
在线时间
24 小时
注册时间
2008-8-5
帖子
1924
8
发表于 2009-9-18 21:07:11 | 只看该作者
clone 只是会拷贝被克隆对象的污染和冻结状态,并不是克隆后必然产生污染和冻结的对象 ^^

  1. v = Viewport.new(0, 0, 12, 12)
  2. a = v.rect
  3. b = v.rect.clone

  4. p a.frozen?, b.frozen?
  5. p a.tainted?, b.tainted?
复制代码
另外即便是污染或者冻结,前者和安全等级有关,禁止了对对象的一些操作;而后者是使对象不可修改,“clone产生的实例被修改了,会影响到原实例. 但是源实例被修改了,则clone产生的实例不会受到影响”这个结论是从何而来?
回复 支持 反对

使用道具 举报

Lv1.梦旅人

风之塞尔达

梦石
0
星屑
50
在线时间
57 小时
注册时间
2005-10-22
帖子
2492

贵宾

9
发表于 2009-9-18 22:43:56 | 只看该作者
“clone产生的实例被修改了,会影响到原实例. 但是源实例被修改了,则clone产生的实例不会受到影响”
紫苏 发表于 2009-9-18 21:07

我前面已经说了 这个只是我的理解...
Copies the frozen and tainted state of OBJ.
也就是第一段代码的运行结果.
a = Viewport.new
b = a.rect.clone
c = a.rect.clone
b或c修改,a的值会改变.   而a的值修改,b与c值不改变
再如

  1. class Klass
  2.    attr_accessor :str
  3. end
  4. s1 = Klass.new      #=> #<Klass:0x401b3a38>
  5. s1.str = "Hello"    #=> "Hello"
  6. s2 = s1.clone       #=> #<Klass:0x401b3998 @str="Hello">
  7. s2.str[1,4] = "i"   #=> "i"
  8. s1.inspect          #=> "#<Klass:0x401b3a38 @str=\"Hi\">"
  9. s2.inspect          #=> "#<Klass:0x401b3998 @str=\"Hi\">"
复制代码
但是如果单独的Rect.new.clone就不会有这种效果 = =
在程序里延续塞尔达的传说, 在画板上勾勒塞尔达的轮廓!!
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
61
在线时间
24 小时
注册时间
2008-8-5
帖子
1924
10
发表于 2009-9-18 23:03:08 | 只看该作者
呵呵,我前面也说了,clone 只是拷贝被克隆体的污染和冻结状态而已,如果被克隆体本身就不是污染和冻结状态,克隆之后自然也不是……所以上面给出了调用 tainted? 和 frozen? 方法的代码,就是为了看克隆体是否有这两个状态的~

另外 Klass 这段代码和这贴讨论的不搭界——
首先 s1 是一个 Klass 的实例,并让其 str 成员指向了 "Hello" 对象;s2 是 s1 的克隆体,拷贝了其所有的成员变量,但这是一个浅层拷贝,s2 的 str 成员实际上指向的还是 s1 的 str 对象,也就是之前的那个 "Hello",换句话说就是这里的浅层拷贝仅仅拷贝的是对象在栈中的引用,而并没有在堆中实际拷贝一份对象的数据(值)~
  1. class Klass
  2.    attr_accessor :str
  3. end

  4. s1 = Klass.new
  5. s1.str = "Hello"
  6. s2 = s1.clone

  7. p s1.str.id, s2.str.id    # 对象 id 一致
复制代码
而这贴讨论的 Rect 问题,其属性按理说只有四个整型变量,那么普通的浅层拷贝就能做到值的拷贝了,但实际上还是有我们都看到的这个问题……(所以上面我才猜测可能是和拷贝了指向整型数据的指针有关)
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2025-1-6 20:23

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表