【问题标题】:Why aren't hot-swappable vtables a popular language feature?为什么热插拔 vtables 不是流行的语言功能?
【发布时间】:2010-12-28 12:30:56
【问题描述】:

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

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

这在 C++ 和 D 编程语言中是可破解的,因为指针可以任意转换,但它是如此丑陋且难以理解,以至于我害怕在需要被其他人理解的代码中这样做。为什么通常不提供更高级别的方法来执行此操作?

【问题讨论】:

    标签: oop pointers language-design virtual-functions


    【解决方案1】:

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

    【讨论】:

    • 在 Smalltalk 中,您甚至可以使用 primitiveChangeClassTo: 更改对象的类,因此无需像在 Python 或 Perl 中那样使用 become 来模拟这一点。
    【解决方案2】:

    你说的是monkey patching,它有几种高级动态语言:

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

    【讨论】:

    • 其实我知道猴子补丁,但是猴子补丁改变了一个类定义。我的想法改变了单个实例的类型。
    【解决方案3】:

    因为大多数语言设计者的思维定势太固定了。

    虽然这些功能在程序员手中是危险的,但它们是库构建者的必要工具。例如,在 Java 中,无需调用构造函数即可创建对象(是的,您可以!)但这种能力只授予库设计者。然而,许多库设计者会为之扼杀的特性在 Java 中是不可能实现的。另一方面,C# 在每个版本中添加了越来越多的动态特性。我真的很期待可以使用即将推出的 DLR(动态语言运行时)构建的所有很棒的库。

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

    object primitiveChangeClassTo: anotherObject
    

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

    【讨论】:

    • 究竟是什么能力使库设计者能够在不调用构造函数的情况下创建对象?
    • @FredOverflow 在 Java 附带的一些 sun 库中查找 Unsafe.allocateInstance()。它用于反序列化对象。
    【解决方案4】:

    套用 XoTcl 文档的话说,这是因为大多数宣称“面向对象”的语言都不是——它们是面向类的。听起来 XoTcl 混合、Ruby 混合和 Perl6 角色提供了您正在寻找的功能。

    【讨论】:

      【解决方案5】:

      您可以在 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 编程中,我从未使用过它,也从未见过其他人使用它。恕我直言,随意使用此功能会使您的代码难以维护和调试,这是一个巨大的危险。

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

      【讨论】:

      • 更改对象的类对于代码的“热交换”最有用,即在系统运行时用新代码更新系统。在 Smalltalk 中,这是一种非常常见的技术(隐藏在一个不错的 API 后面的库中)不要知道它在 python 中有多常见。
      猜你喜欢
      • 2018-10-01
      • 2010-12-28
      • 1970-01-01
      • 2017-10-28
      • 2016-01-22
      • 2011-03-14
      • 2016-01-31
      • 1970-01-01
      • 2010-12-06
      相关资源
      最近更新 更多