我试图了解以下问题的答案在所有主要OOP语言中是否相同;如果没有,那么这些语言有何不同。
假设我有一个定义方法A
和act
的课程jump
;方法act
调用方法jump
。 A
的子类B
会覆盖方法jump
(即,使用适当的语法来确保在调用jump
时,类B
中的实现是使用)。
我有类b
的对象B
。我希望它的行为与类A
完全相同。换句话说,我希望使用jump
中的实现执行A
。我有哪些不同语言的选择?
例如,我可以通过某种形式的向下转换实现这一目标吗?或者也许通过创建一个知道要调用哪些方法的代理对象?
我希望避免创建类A
的全新对象,并仔细设置a
和b
之间的内部状态共享,因为这显然不是面向未来的,并且复杂。我还想避免将b
的状态复制到类A
的全新对象中,因为可能需要复制大量数据。
更新
我问了这个问题specifically about Python,但似乎这在Python 中是不可能实现的,从技术上来说它可以完成......有点......
除了技术可行性之外,似乎还有一个强烈的争论,即从设计的角度来做这件事。我在a separate question中问过这个问题。
答案 0 :(得分:2)
评论重申:首选组合而不是继承。
当您的子类与其超类具有明确定义的行为差异时,继承很有效,但是您经常会遇到该模型变得笨拙或停止有意义的点。那时,你需要重新考虑你的设计。
组合通常是更好的解决方案。将对象的不同行为委派给不同的对象(或多个对象)可以减少或消除对子类化的需要。
在您的情况下,A类和B类之间的行为差异可以封装在策略模式中。然后,您可以在实例级别更改A类(和B类,如果仍然需要)的行为,只需指定新策略即可。
策略模式在短期内可能需要更多代码,但它是干净且可维护的。方法调整,猴子修补,以及允许我们在特定语言实现中使用的所有那些很酷的东西都很有趣,但是出现意外副作用的可能性很高,代码往往难以维护。
答案 1 :(得分:1)
您所询问的内容与OOP编程完全无关/不受支持。
如果使用类A
将对象B
子类化并覆盖其方法,则在创建B
的具体实例时,将基本方法的所有覆盖/新实现关联用它(要么我们谈论Java或C ++与虚拟表等)。
您已实例化对象B
如果你覆盖了那个方法,为什么你会期望你能够/将/应该能够调用超类的方法?
你当然可以明确地称它为例如通过在方法中调用super
,但你不能自动执行,并且转换也无法帮助你做到这一点。
我无法想象你为什么要那样做
如果您需要使用课程A
,请使用课程A
如果需要覆盖其功能,请使用其子类B
。
答案 2 :(得分:0)
大多数编程语言都有一些麻烦来支持虚函数的动态调度(在子类而不是父类的实现中调用重写方法jump
的情况) - 达到解决它的程度或者避免这很困难。一般来说,专业化/多态性是一个理想的特征 - 可以说是OOP的首要目标。
查看关于Virtual Functions的维基百科文章,该文章提供了许多编程语言中对虚函数支持的有用概述。在考虑特定语言时,它将为您提供一个开始的位置,以及在查看程序员可以控制调度行为的语言时权衡的权衡(例如,参见C ++部分)。
如此松散,你的问题的答案是,“不,所有编程语言中的行为都不一样。”此外,没有语言独立的解决方案。如果您需要行为,C ++可能是您最好的选择。
答案 3 :(得分:0)
你实际上可以用Python(某种程度)做这件事,有些可怕的黑客攻击。它要求您实现类似我们在您的第一个特定于Python的问题中讨论的包装器,但作为B 的子类。然后,您还需要实现写代理(包装器对象不应该包含通常与类层次结构相关联的任何状态,它应该将所有属性访问重定向到B的基础实例。
但是,不是将方法查找重定向到A然后使用包装实例调用方法,而是调用将包装器对象作为self
传递的方法。这是合法的,因为包装类是B的子类,因此包装器实例是您正在调用其方法的类的实例。
这将是非常奇怪的代码,要求您同时使用IS-A和HAS-A关系动态生成类。它可能也会变得相当脆弱并且在很多极端情况下都会产生奇怪的结果(你通常不能在Python中编写100%完美的包装类,因为这种奇怪的东西是可能的)。
我完全抛开天气这是个好主意。