5

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

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

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

4

5 回答 5

3

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

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

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

object primitiveChangeClassTo: anotherObject

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

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

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

于 2009-12-20T19:01:26.017 回答
1

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

于 2009-12-20T16:41:09.817 回答
1

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

于 2009-12-20T18:29:16.270 回答
0

你说的是猴子补丁,它有几种高级动态语言:

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

于 2009-12-20T16:55:51.413 回答