2009-12-20 77 views
4

在面向对象的程序设计,它有时很高兴能够修改一个已经创建的对象的行为。当然,这可以通过比较详细的技术来完成,例如战略模式。然而,有时候通过在实例化之后改变vtable指针来完全改变对象的类型将会很好。这将是在确保安全的,假设你从类A切换到B类:为什么不可热插拔的vtables成为热门语言功能?

  1. B类是A类的子类,不添加任何新的领域,或
  2. B类和A类有相同的父类。除了覆盖父类的虚拟函数之外,其他都不做任何事情。 (无新字段或虚函数。)
  3. 在任一情况下,A和B必须具有相同的不变量。

这在C++和D编程语言中是可以破解的,因为指针可以被任意地强制转换,但它太难看了,难以遵循,所以我很害怕在代码中这样做,它需要被理解还有谁。为什么不是通常提供的更高级的方法?

回答

3

因为大多数语言设计师的思维模式太静态。

虽然这些特征在程序员之手的危险,他们是图书馆的建设者必要的工具。例如,在Java中,人们可以在不调用构造函数的情况下创建对象(是的,你可以!),但是这种功能只能提供给库设计人员。然而,图书馆设计人员为杀死Java的许多功能是不可能的。另一方面,C#在每个版本中都增加了越来越多的动态功能。我非常期待可以使用即将推出的DLR(动态语言运行库)构建的所有优秀库。

在一些动态语言如Smalltalk(也因为据我所知,Perl和Python,但不是红宝石),这是完全可以改变一个对象的类。在菲罗Smalltalk中你

object primitiveChangeClassTo: anotherObject 

从而改变类的object到的anotherObject实现这一目标。请注意,这与object become: anotherObject不一样,它交换了两个对象的所有指针。

+0

确切地说,什么能力使库设计者能够在不调用构造函数的情况下创建对象? – fredoverflow 2012-08-12 12:01:04

+0

@FredOverflow在Java附带的一些sun库中查找'Unsafe.allocateInstance()'。它用于反序列化对象。 – akuhn 2012-09-17 22:19:43

1

你可以做到这一点在高级语言 - 看到Smalltalk的“变”的消息。即使在ST中,这个特性几乎不可能正确使用的事实可能是像C++这样的静态类型语言不支持它的原因。

+0

在Smalltalk中,您甚至可以使用'primitiveChangeClassTo:'更改对象的类,因此不需要像在Python或Perl中那样使用“成为变形”来模拟。 – akuhn 2009-12-20 17:24:42

0

什么你所谈论的是monkey patching,即在几个高级的动态语言可供选择:

猴子补丁(也说明 猴子补丁,猴补丁)是一种能够 扩展或修改动态语言(例如Smalltalk, JavaScript,Objective-C,Ruby,Perl, Python,Groovy等)的运行时代码,而不改变原始源代码 。

+0

我实际上知道猴子补丁,但猴子补丁修改了一个类**定义**。我想要的是改变一个**实例**的类型。 – dsimcha 2009-12-20 17:02:57

+2

哦,我明白了,我的错误。 – Klaim 2009-12-20 17:20:33

0

要套用XoTcl文档,这是因为它宣告大多数语言中是“面向对象”都没有 - 他们是面向类。听起来像XoTcl mixin,Ruby mixins和Perl6角色提供了你正在寻找的功能。

2

你可以做到这一点在Python中,通过修改实例__class__属性:

>>> class A(object): 
...  def foo(self): 
...   print "I am an A" 
... 
>>> 
>>> class B(object): 
...  def foo(self): 
...   print "I am a B" 
... 
>>> 
>>> a = A() 
>>> a.foo() 
I am an A 

>>> a.__class__ 
<class '__main__.A'> 

>>> a.__class__ = B 
>>> 
>>> a 
<__main__.B object at 0x017010B0> 
>>> a.foo() 
I am a B 

然而12年Python编程的我从未有过使用它,从来没见过任何人使用它。恕我直言,有一个巨大的危险,偶然使用这个功能将使你的代码难以维护和调试。

我可以想象使用它的唯一情况是用于运行时调试,例如,将创建我没有控制权的类的实例更改为模仿对象或更改为已使用日志装饰的类。我不会在生产代码中使用它。

+0

更改对象的类对于代码的“热交换”非常有用,即在系统运行时用新代码更新系统。在Smalltalk中,这是一种非常常见的技术(隐藏在一个漂亮的API背后的图书馆中),不管它在Python中有多普遍。 – akuhn 2009-12-20 20:05:47