Java忽略了多重继承,因为它消除了保持语言简单性的设计目标。
我想知道Java(及其生态系统)是否真的“简单”。Python并不复杂,具有多重继承。因此,我的问题不是太主观,而是...
从旨在大量使用多重继承的代码中受益的典型问题模式有哪些?
Java忽略了多重继承,因为它消除了保持语言简单性的设计目标。
我想知道Java(及其生态系统)是否真的“简单”。Python并不复杂,具有多重继承。因此,我的问题不是太主观,而是...
从旨在大量使用多重继承的代码中受益的典型问题模式有哪些?
Answers:
优点:
缺点:
在C ++中,用于组合正交特征的多重继承的一个很好的例子是,当您使用CRTP来为游戏设置组件系统时。
我已经开始写一个例子,但我认为更值得一看的是真实世界的例子。Ogre3D的某些代码以一种非常直观的方式使用了多重继承。例如,Mesh类从Resources和AnimationContainer继承。资源公开了所有资源共有的接口,而AnimationContainer公开了特定于操纵一组动画的接口。它们不相关,因此很容易将网格视为一种资源,并且可以包含一组动画。感觉自然吗?
您可以查看该库中的其他示例,例如通过使类继承自CRTP类的变体(使 new和delete重载)继承来以细粒度的方式管理内存分配的方式。
如前所述,多重继承的主要问题来自混合相关概念。这使得该语言必须设置复杂的实现(请参见C ++允许解决钻石问题的方式...),并且用户不确定该实现中发生了什么。例如,阅读本文解释如何在C ++中实现它。
从语言中删除它有助于避免不知道该如何使这种语言变得糟糕的人们。但这迫使人们以一种有时不自然的方式进行思考,即使是极端情况,您也可能会想起来。
有一个叫做mixin的概念,在更动态的语言中大量使用。多重继承是语言支持混合的一种方式。Mixins通常用作类累积不同功能的一种方式。如果没有多重继承,则必须使用聚合/委托来获得类的mixin类型行为,这在语法上会更加繁琐。
我在这里不会做过多的工作,但是您可以通过以下链接http://docs.python.org/release/1.5.1p1/tut/multiple.html一定可以理解python中的多重继承:
解释语义的唯一必要规则是用于类属性引用的解析规则。这是深度优先,从左到右。因此,如果在DerivedClassName中找不到属性,则在Base1中搜索该属性,然后(递归)在Base1的基类中,并且只有在该属性中找不到该属性时,才在Base2中搜索它,依此类推。
...
显然,考虑到Python依赖于约定来避免意外的名称冲突,因此不加选择地使用多重继承是一个维护噩梦。多重继承的一个众所周知的问题是一个派生自两个类的类,而这两个类恰好具有相同的基类。尽管很容易弄清楚在这种情况下会发生什么(实例将具有一个``实例变量''或通用基类使用的数据属性的单个副本),但尚不清楚这些语义是否以任何方式有用。
这只是一小段,但足够大,可以消除我的猜疑。
从旨在大量使用多重继承的代码中受益的典型问题模式有哪些?
这只是一个例子,但我发现一个例子对于提高安全性和减轻在调用者或子类上应用级联更改的诱惑是无价的。
我发现即使对于最抽象的无状态接口,多重继承也非常有用,它是C ++中的非虚拟接口习惯用法(NVI)。
他们甚至没有真正的抽象基类这么多的接口有实现向他们保证合同的通用方面只是一点点,因为他们没有真正缩小合同的一般性这么多,因为更好的执行它。
一个简单的例子(有些人可能会检查传入的文件句柄是否打开或类似的东西):
// Non-virtual interface (public methods are nonvirtual/final).
// Since these are modeling the concept of "interface", not ABC,
// multiple will often be inherited ("implemented") by a subclass.
class SomeInterface
{
public:
// Pre: x should always be greater than or equal to zero.
void f(int x) /*final*/
{
// Make sure x is actually greater than or equal to zero
// to meet the necessary pre-conditions of this function.
assert(x >= 0);
// Call the overridden function in the subtype.
f_impl(x);
}
protected:
// Overridden by a boatload of subtypes which implement
// this non-virtual interface.
virtual void f_impl(int x) = 0;
};
在这种情况下,也许f
被代码库中的一千个位置调用,而f_impl
被一百个子类覆盖。
在所有呼叫的1000个位置f
或所有覆盖的100个位置中很难进行这种安全检查f_impl
。
通过仅使此入口指向非虚拟功能,它为我提供了进行此检查的中心位置。这种检查并没有丝毫减少抽象,因为它只是断言了调用此函数所需的前提条件。从某种意义上讲,它可以说是增强了接口提供的协定,并减轻了检查x
输入以确保其在覆盖它的所有100个地方都符合有效前提条件的负担。
我希望每种语言都具有,甚至在C ++中,也希望它是一个本机概念(例如:不需要我们定义一个单独的函数来覆盖)。
如果您没有assert
事先这样做,这非常有用,并且意识到以后在代码库中的某些随机位置遇到负值传递给时需要使用它f
。