关于.net:为什么C#中都存在抽象类和接口?

Why do both the abstract class and interface exist in C#?

如果我们可以通过将类中的所有成员都抽象化来实现接口特性,那么为什么抽象类和接口都存在于C中呢?

是因为:

  • 接口存在以具有多个继承
  • 有接口是有意义的,因为对象的can-do特性应该放在接口中,而不是基本抽象类中。
  • 请澄清


    抽象类可以指定一些实现,但通常不是全部。(已经说过了,提供一个没有抽象成员的抽象类是完全可能的,但是有很多虚拟成员没有"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() {}
    }

    Derived派生的类不能再重写Foo

    我并不是说我想要实现的多重继承——但是如果我们拥有它(连同它的复杂性),那么一个刚刚包含抽象方法的抽象类几乎可以完成接口所做的一切。(有一个关于显式接口实现的问题,但这就是我目前所能想到的。)


    这不是一个微不足道的问题,这是一个非常好的问题,我总是问我面试的任何候选人。简而言之,抽象基类定义了类型层次结构,而接口定义了契约。

    您可以看到它是一个vs实现的。即Account可以是一个抽象的基础帐户,因为您可以有一个CheckingAccount、一个SavingsAccount等,所有这些都是从抽象的基础类Account派生的。抽象基类也可以像任何普通类一样包含非抽象方法、属性和字段。但是,接口只包含必须实现的抽象方法和属性。

    让我们只从一个基类派生单一继承,就像Java一样。然而,您可以实现任意多的接口——这是因为接口只是您的类承诺实现的契约。

    因此,如果我有一个类SourceFile,那么我的类可以选择实现ISourceControl,它表示"我忠实地承诺实现ISourceControl要求的方法和属性"。

    这是一个很大的领域,可能比我给的更好的职位更值得,但是我的时间很短,但我希望这有帮助!


    它们都存在是因为它们都是非常不同的东西。抽象类允许实现,接口不允许。接口非常方便,因为它允许我说一些关于我正在构建的类型的事情(它是可序列化的,它是可食用的,等等),但是它不允许我为我定义的成员定义任何实现。

    抽象类比接口更强大,因为它允许我通过抽象和虚拟成员创建继承接口,但如果我选择的话,还提供某种默认或基本实现。然而,正如蜘蛛人所知,有了这种强大的力量,责任就来了,因为抽象类在架构上更脆弱。

    旁注:值得注意的是,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";
        }
    }

    不能,因为一个类不能从多个类派生。


    接口用于类可以做什么,但也用于隐藏类可以做的一些事情。

    例如,IEnumerable接口描述一个类可以迭代它的成员,但它也限制了对这个单一功能的访问。List也可以按索引访问项目,但是当您通过IEnumerable接口访问它时,您只知道它可以迭代成员。

    如果一个方法接受IEnumerable接口作为参数,这意味着它只与遍历成员的能力相关。您可以使用几个具有此功能的不同类(如List或数组T[],而不需要为每个类使用一个方法。

    一个方法不仅可以接受实现一个接口的几个不同的类,还可以创建实现该接口的新类,而且该方法也会很乐意接受这些类。


    它们有两个截然不同的用途。

    抽象类提供了一种方法,使对象继承自定义的约定,并允许在基类中指定行为。从理论角度来看,这提供了一种IS-A关系,即具体类是一种特定类型的基类。

    接口允许类定义一个(或多个)它们将要实现的契约。它们允许"作为"或"可以作为"类型的关系,而不是直接继承。这就是为什么接口通常使用形容词,因为它们是名称(idisposable)而不是名词。


    abstractclass可以有一个实现,而interface只允许您创建一个实现者必须遵循的合同。使用抽象类,可以为它们的子类提供一个公共行为,而不使用接口。


    接口定义了一个实现类必须实现的契约;它是一种声明"这就是它"的方法。抽象类是一个类的部分实现,根据定义,它是不完整的,需要完成一个删除。它们是非常不同的东西。