Why do both the abstract class and interface exist in C#?
如果我们可以通过将类中的所有成员都抽象化来实现接口特性,那么为什么抽象类和接口都存在于C中呢?
是因为:
请澄清
抽象类可以指定一些实现,但通常不是全部。(已经说过了,提供一个没有抽象成员的抽象类是完全可能的,但是有很多虚拟成员没有"op"实现)。接口不提供实现,只提供契约。
您当然可以认为,如果允许多个类继承,那么接口在很大程度上是无意义的。
就我个人而言,我不会因为遗产的"IS-A"和"can do"而被挂断电话。它从来没有给我一个很好的直觉去做什么,仅仅是玩弄不同的想法,看看哪个想法最灵活。(再说一次,我是一个非常喜欢组合而不是继承的人…)
编辑:就像反驳卢布什金评论中第三点最方便的方式一样…通过将抽象方法密封,可以用非虚拟方法重写它(就不能进一步重写它而言):
1 2 3 4 5 6 7 8 9 | public abstract class AbstractBase { public abstract void Foo(); } public class Derived : AbstractBase { public sealed override void Foo() {} } |
从
我并不是说我想要实现的多重继承——但是如果我们拥有它(连同它的复杂性),那么一个刚刚包含抽象方法的抽象类几乎可以完成接口所做的一切。(有一个关于显式接口实现的问题,但这就是我目前所能想到的。)
这不是一个微不足道的问题,这是一个非常好的问题,我总是问我面试的任何候选人。简而言之,抽象基类定义了类型层次结构,而接口定义了契约。
您可以看到它是一个vs实现的。即
让我们只从一个基类派生单一继承,就像Java一样。然而,您可以实现任意多的接口——这是因为接口只是您的类承诺实现的契约。
因此,如果我有一个类
这是一个很大的领域,可能比我给的更好的职位更值得,但是我的时间很短,但我希望这有帮助!
它们都存在是因为它们都是非常不同的东西。抽象类允许实现,接口不允许。接口非常方便,因为它允许我说一些关于我正在构建的类型的事情(它是可序列化的,它是可食用的,等等),但是它不允许我为我定义的成员定义任何实现。
抽象类比接口更强大,因为它允许我通过抽象和虚拟成员创建继承接口,但如果我选择的话,还提供某种默认或基本实现。然而,正如蜘蛛人所知,有了这种强大的力量,责任就来了,因为抽象类在架构上更脆弱。
旁注:值得注意的是,vance morrrison(clr团队的成员)推测在将来的clr版本中,要将默认方法实现添加到接口中。这将大大模糊接口和抽象类之间的区别。有关详细信息,请参阅此视频。
两种机制之所以存在,一个重要的原因是因为C...NET只允许单个继承,而不是像C++那样的多重继承。类继承允许您只从一个地方继承实现;其他一切都必须通过实现接口来完成。
例如,假设我创建了一个类,比如car,我将其分为三个子类:rearwheeldrive、frontwheeldrive和allwheeldrive。现在我决定,我需要将我的课程沿着不同的"轴"剪切,就像那些有按钮启动器和没有按钮启动器的。我希望所有按钮启动汽车都有一个"pushstartbutton()"方法,而非按钮汽车有一个"turnkey()"方法,我希望能够处理汽车对象(关于启动它们),不管它们是哪个子类。我可以定义我的类可以实现的接口,例如ipushButtonStart和ikeyedignition,因此我有一种处理我的对象的通用方法,这种方法不同于每个派生的单个基类。
接口的存在是为了提供一个没有任何实现的类,这样.NET就可以在托管环境中为安全和功能性的多重继承提供支持。
你已经给出了一个很好的答案。我认为你的第二个答案才是真正的原因。如果我想使一个对象具有可比性,就不必从可比的基类派生。如果你考虑到所有的接口,想想你需要处理的所有排列,比如IComparable的基本接口。
接口允许我们围绕对象提供的公开行为定义契约。抽象类允许您定义行为和实现,这是一个非常不同的东西。
这个想法很简单——如果你的类(your class)已经从父类(someparentclass)派生出来,同时你希望你的类(yourclass)有一个在某个抽象类(someabstractclass)中定义的新行为,你不能简单地从该抽象类(someabstractclass)派生,c不允许在仪式。但是,如果您的新行为是在接口(iyorinterface)中定义的,那么您可以很容易地从接口(iyorinterface)和父类(someParentClass)派生。
考虑拥有由两个孩子(苹果和香蕉)衍生的类水果,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Fruit { public virtual string GetColor() { return string.Empty; } } class Apple : Fruit { public override string GetColor() { return"Red"; } } class Banana : Fruit { public override string GetColor() { return"Yellow"; } } |
我们有一个可在C中调用的现有接口。此接口具有如下所示的单个方法,实现此接口的类保证可以克隆该接口:
1 2 3 4 | public interface ICloneable { object Clone(); } |
号
现在,如果我想使我的apple类(而不是banana类)可克隆,我可以简单地实现这样的可克隆:
1 2 3 4 5 6 7 8 9 10 11 12 | class Apple : Fruit , ICloneable { public object Clone() { // add your code here } public override string GetColor() { return"Red"; } } |
现在考虑一下纯抽象类的论点,如果C有纯抽象类,那么说Clonable而不是Interface IClonable,如下所示:
1 2 3 4 | abstract class Clonable { public abstract object Clone(); } |
。
你现在能通过继承抽象的可克隆而不是IClonable使你的apple类成为可克隆的吗?这样地:
1 2 3 4 5 6 7 8 9 10 11 12 13 | // Error: Class 'Apple' cannot have multiple base classes: 'Fruit' & 'Clonable' class Apple : Fruit, Clonable { public object Clone() { // add your code here } public override string GetColor() { return"Red"; } } |
不能,因为一个类不能从多个类派生。
接口用于类可以做什么,但也用于隐藏类可以做的一些事情。
例如,
如果一个方法接受
一个方法不仅可以接受实现一个接口的几个不同的类,还可以创建实现该接口的新类,而且该方法也会很乐意接受这些类。
它们有两个截然不同的用途。
抽象类提供了一种方法,使对象继承自定义的约定,并允许在基类中指定行为。从理论角度来看,这提供了一种IS-A关系,即具体类是一种特定类型的基类。
接口允许类定义一个(或多个)它们将要实现的契约。它们允许"作为"或"可以作为"类型的关系,而不是直接继承。这就是为什么接口通常使用形容词,因为它们是名称(idisposable)而不是名词。
接口定义了一个实现类必须实现的契约;它是一种声明"这就是它"的方法。抽象类是一个类的部分实现,根据定义,它是不完整的,需要完成一个删除。它们是非常不同的东西。