为什么热插拔vtables不是一种流行的语言功能?

时间:2009-12-20 16:35:40

标签: oop pointers language-design virtual-functions

在面向对象的编程中,能够修改已创建对象的行为有时会很好。当然,这可以通过相对冗长的技术来完成,例如策略模式。但是,有时通过在实例化后更改vtable指针来完全更改对象的类型会更好。如果假设你从A级转换到B级,这将是安全的:

  1. B类是A类的子类,不添加任何新字段,或
  2. B类和A类具有相同的父类。除了从父类重写虚函数之外,都不做任何事情。 (没有新字段或虚拟功能。)
  3. 在任何一种情况下,A和B必须具有相同的不变量。
  4. 这在C ++和D编程语言中是可以攻击的,因为指针可以随意转换,但是它太丑陋且难以理解,我害怕在需要其他人理解的代码中执行此操作。为什么通常不提供更高级别的方法?

5 个答案:

答案 0 :(得分:3)

因为大多数语言设计师的心态太过静态。

虽然这些功能在程序员手中很危险,但它们是图书馆建设者的必备工具。例如,在Java中,可以在不调用构造函数的情况下创建对象(是的,您可以!)但这种功能仅提供给库设计者。尽管如此,图书馆设计人员可能会杀死的许多功能都是Java无法实现的。另一方面,C#在每个版本中添加越来越多的动态功能。我真的很期待使用即将推出的DLR(动态语言运行时)构建的所有可用库。

在一些动态语言中,例如Smalltalk(据我所知Perl和Python,但不是Ruby),完全可以更改对象的类。在Pharo Smalltalk中,您可以通过

实现这一目标
object primitiveChangeClassTo: anotherObject

object的类更改为anotherObject的类。请注意,这与交换两个对象的所有指针的object become: anotherObject不同。

答案 1 :(得分:2)

您可以通过修改实例__class__属性

在Python中执行此操作
>>> 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编程中,我从来没有使用它,也从未见过其他人使用它。恕我直言,随意使用此功能将使您的代码难以维护和调试存在巨大危险。

我可以想象使用它的唯一情况是运行时调试,例如将创建我无法控制的类的实例更改为模拟对象或已更改为使用日志记录的类。我不会在生产代码中使用它。

答案 2 :(得分:1)

您可以使用更高级别的语言 - 请参阅Smalltalk“成为”消息。即使在ST中这个功能几乎不可能正确使用的事实可能是像C ++这样的静态类型语言不支持它的原因。

答案 3 :(得分:1)

用XoTcl文档来解释,这是因为大多数宣称“面向对象”的语言都不是 - 它们是面向类的。听起来像XoTcl mixins,Ruby mixins和Perl6角色提供了您正在寻找的功能。

答案 4 :(得分:0)

您所谈论的是monkey patching,可以使用多种高级动态语言:

  

猴子补丁(也拼写   猴子补丁,MonkeyPatch)是一种方式   扩展或修改运行时代码   动态语言(例如Smalltalk,   JavaScript,Objective-C,Ruby,Perl,   Python,Groovy等)无需改变   原始源代码。