根据Herb Sutter的说法,应该更喜欢抽象接口(所有纯虚函数)而不是C ++中的抽象类,以尽可能地实现分离。虽然我个人认为该规则非常有用,但是最近我加入了一个由许多Java程序员组成的团队,并且在Java代码中似乎没有该准则。函数及其实现通常位于抽象类中。因此,即使对于C ++,我也将Herb Sutter弄错了吗?还是与Java相比,C ++中抽象函数的用法是否存在一般差异?在Java中,带有实现代码的抽象类比在C ++中更明智吗?如果是,为什么呢?
根据Herb Sutter的说法,应该更喜欢抽象接口(所有纯虚函数)而不是C ++中的抽象类,以尽可能地实现分离。虽然我个人认为该规则非常有用,但是最近我加入了一个由许多Java程序员组成的团队,并且在Java代码中似乎没有该准则。函数及其实现通常位于抽象类中。因此,即使对于C ++,我也将Herb Sutter弄错了吗?还是与Java相比,C ++中抽象函数的用法是否存在一般差异?在Java中,带有实现代码的抽象类比在C ++中更明智吗?如果是,为什么呢?
Answers:
OOP具有组成和替代。
C ++具有多重继承,模板专门化,嵌入和值/移动/指针语义。
Java具有单一继承和接口,嵌入和引用语义。
OOP学校使用这些语言的常见方式是采用继承进行对象替换,并嵌入进行组合。但是,您还需要一个共同的祖先和一种运行时广播的方式(在C ++中称为dynamic_cast
,在Java中只是从另一个接口请求接口)。
Java通过其自己的java.lang.Object
扎根层次结构来完成所有这些工作。C ++没有预定义的公共根,因此您至少应对其进行定义以产生相同的“图片”(但这限制了某些C ++的可能性...)。
此后,具有编译时多态性(考虑CRTP)和值语义的可能性还可以为“ OOP对象”的概念可以移植到C ++程序中提供其他选择。
您甚至可以想象,使用嵌入和隐式转换来管理替代品和使用私有继承来管理合成的异端,实际上是在颠覆传统的学校范式。(当然,这种方式比其他方式要年轻20岁,因此不要指望这样做会得到广泛的社区支持)
或者,您可以想象所有类的虚拟公共基础,从接口(无实现)到最终类(完全实现),通过部分实现的接口甚至是均匀的接口簇,使用“优势”作为通过“多堆叠”从接口到实现的分派-“平行四边形”继承方案。
假设只有一种,并且只有一种OOP方式会限制两种语言的功能,因此将OOP与Java与C ++进行比较。
强迫C ++严格遵守Java编码习惯会使C ++变性,因为迫使Java像类C ++语言一样行为使Java变性。
这不是两种语言所具有的“敏感性”问题,而是两种语言所具有的不同“聚合机制”,以及将它们组合在一起的不同方式,这使得某些成语在一种语言中比另一种语言更有利可图,反之亦然。
两种语言都适用该原则,但是您没有进行公平的比较。您应该将C ++纯抽象类与Java接口进行比较。
即使在C ++中,您也可以具有实现了某些功能的抽象类,但是这些抽象类是从纯抽象类派生的(没有实现)。在Java中,您将具有相同的抽象类(具有某些实现),这些抽象类可以从接口派生(没有实现)。
通常,相同的面向对象原则适用于Java和C ++。但是,一个很大的不同是C ++支持多重继承,而在Java中,您只能从一个类继承。这就是我认为Java具有接口的主要原因,以补充缺乏多重继承并可能限制您可以使用它的功能(因为对滥用多重继承提出了很多批评)。因此,可能在Java程序员的脑海中,抽象类和接口之间存在更强的区别。抽象类用于共享和继承行为,而接口仅用于添加额外的功能。请记住,在Java中,您只能从一个类继承,但是可以有许多接口。但是,在C ++中,纯抽象类(即“ C ++接口”)是 用于共享和继承行为,与Java接口的目的不同(尽管仍然需要实现这些功能),因此用法与Java接口不同。