接口和仅具有抽象方法的抽象类之间是否有区别?


9

假设我们有一个抽象类,而这个类只有抽象方法。这个抽象类是否不同于仅具有相同方法的接口?

我想知道的是,在仅抽象成员和等效接口的抽象类之间,在哲学上,客观上以及在底层编程语言实现上是否存在差异?


哪种语言?
凯文·克莱恩

据我所知,你的问题的答案重复两次这里这里。而且这两个答案与语言无关,那里没有C#的特定内容
gna 2013年

3
@blank我不同意对您的问题应用的重复状态,因此我重新打开了它。此外,我编辑了您的问题,以进一步阐明我相信您的要求。
maple_shaft

Answers:


22

从技术上讲,这些差异并不是真正重要,但是从概念上讲,它们是完全不同的事物,这导致了其他人提到的技术差异。

抽象超类的确切含义就是它,它是一种常见的类型,许多其他类型都共享这种类型,例如“猫和狗是动物”。

接口也正是它的外表,它是其他类可以与对象进行通信的接口。如果您想让猫走路,可以的,因为猫实现了CanWalk接口。蜥蜴也一样,尽管它们的行走方式非常不同。另一方面,Snake没有实现CanWalk,因此您不能告诉它走路。同时,蜥蜴和蛇(或者可能是更明确的子类-我不是专家)可能都剥皮了,因此实现了CanShed,而猫则无法做到。

但是它们仍然是动物,并且具有一些共同的属性,例如它们是活的还是死的。

这就是为什么接口上的所有方法都必须实现为公共的(或在C#中显式实现)的原因。在与对象接口的类中隐藏的接口的意义是什么?这就是为什么即使语言不支持多重继承,您也可以对一个对象具有多个接口的原因。

回到您的问题,当您以这种方式看待它时,几乎没有理由拥有一个完全抽象的超类。


4
+1,尽管猫掉下来的方式比蛇或蜥蜴更烦人。
马修·弗林

从技术上讲:抽象方法可以设置为受保护的。接口方法不能。
雅克·科特斯

19

在大多数OOP语言中,实现类只能从一个抽象类派生,但是可以实现多个接口。


3
最?您在数哪些?我知道的大多数OOP语言都没有接口或抽象类。C ++只有抽象类。
凯文·克莱恩

10
@kevincline:可能是C#,Java和VB.NET。
tdammers

1
@kevincline,我认为只是缺少了“两者兼而有之”。IIRC在Ada中使用接口的动机是,设计人员不希望使用通用的多重继承功能,但是接口的特殊情况被认为太重要了,无法提供。
AProgrammer

@tdammers:大声笑。那个玩笑吧?
凯文·克莱恩

3

在像C ++这样的语言中,它允许多重继承,并且没有接口,所有方法都抽象的抽象类可以用作接口。我使用C ++的工作不是很多,但是我猜想,当基类中有同名的方法时,多重继承会引起问题。

在PHP和C#之类的语言中,接口提供了一种实现类似的多态性的方法,尽管我不喜欢将其称为“继承”,因为在继承抽象类和实现接口之间存在概念上的差异。接口消除了冲突问题,因为它们本身不提供任何实现。

接口是与外界的契约,而抽象类可以提供实现,尽管如果用于“伪造”接口,则很可能不会。

主要的概念差异是,当一个类继承另一个类(是否抽象)时,存在“ is”关系,因此a Car是a VehicleDogis an Animal。使用接口,对象要做的事情很重要。所以罐子CarDog罐子Move()以及消费者都知道这是因为他们实施了Movable,但是汽车绝对不是a Dog或an Animal。而且move的实现会有所不同(轮子与腿),但是使用代码并不在乎,也不在乎。接口都是关于消耗代码的,而不是实现。

要点是,如果您有使用自己选择的语言的接口,请将其用于存在的用途。如果不是这样(例如在C ++中),则可以使用纯抽象类来伪造它们。


接口是一种类型一样,所以你可以有一个IAnimal这两个DogCat
艾米·布兰肯希

您可以,但是我认为,接口与暴露给外界的行为有关,而与对象是什么无关。继承意味着某种事物是另一种事物的类型(猫是动物)。接口仅说明该对象可以做什么。这就是为什么我喜欢说某种“实现”而不是“继承自”接口的原因,这是我工作过的大多数.Net人员都会说的(我想是因为继承和实现的语法相同)。
伊万·平塔尔

2

抽象类可能具有受抽象保护的方法(以我正在使用的语言),在接口中,方法通常总是公共的。这种差异是否允许有用的利用,我不知道。

编辑我首先认为私有抽象方法没有用,但现在我回想起可以将其用于确保从不调用该方法。这样,您可以防止调用对象的副本构造函数。


1
受保护的虚拟(可重写)方法对于属于框架或类似内容的类很有用。这样,他们可以确保继承抽象的类中的自定义代码提供该功能。尽管也可以通过继承基类上的接口但不实际实现其方法来实现
Ivan Pintar 2013年

是的,我当时正在考虑类似的事情,但是没有任何经验,因此无法判断。感谢您的输入。
Thomas

请注意。在某些语言中,私有虚拟方法可以在派生类中重写。
JohanBoulé2014年

2

是的,它们是不同的。否则,语言设计师将不会同时提供这两种语言。我知道两种将类和接口分开的语言:Java和C#,Java的突变体。设计人员创建了接口,以避免支持多个类继承。大多数其他语言都支持多种类继承,因此不会将类和接口分开。


2

我认为主要区别在于:在抽象类中-即使所有方法都是抽象的,它们仍然可以为实现它的类提供数据成员(实例变量)和一些代码(以私有方法或构造函数的形式),静态块;为子类做部分工作并帮助他们实施。

一个积极的副作用:代码在一个地方,所以一个地方可以进行更正。子类可以只调用父类方法,然后在父类动作足以满足其情况的情况下执行其他操作或不执行任何操作。超级类希望每个子类都做出此决定,因此已将其所有实现标记为抽象(有些可能也为空)

与问题无关:但是具有接口意味着一个类可以实现两个不同的合同。因此,与抽象超类相比,这是接口的优点


1
是否在没有任何实现的情况下定义抽象方法,并将实现留给继承的类?
伊万·平塔尔

是的,您的权利那么,我想它就是变量,构造函数以及静态和私有方法(如果您算在内)
tgkprog 2013年

@Pinetree,在大多数情况下,实际上,您通常需要在抽象类中至少包含一些“真实”代码(至少使用我使用的语言,该语言没有抽象类的特殊构造)。
艾米·布兰肯希

@AmyBlankenship是的,大多数时候抽象类确实具有“真实”代码(这就是它们的用处)。但是我是在纯抽象类的上下文中指的是抽象方法,纯抽象类充当像C ++这样的没有接口的语言的接口。
伊万·平塔尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.