C# 简单基类和抽象类之间的区别是什么?

C# 简单基类和抽象类之间的区别是什么?,c#,.net,abstract-class,base-class,C#,.net,Abstract Class,Base Class,我当时正在做一种研发工作,对抽象类的概念感到困惑 我所知道的抽象类可能包含具体方法,也可能包含虚拟方法。它可能包含也可能不包含抽象方法,它可能包含字段并限制实例的直接创建 但是,我们可以在一个简单的基类中实现所有这些(添加虚拟方法会起到很大作用,因为一个基类包含虚拟方法,而虚拟方法不包含实现,并且重写与抽象方法相同)。那么为什么我们需要一个抽象类,尽管接口支持多继承和事件?主要区别在于编译器不允许您实例化抽象类,而您可以实例化基类(这可能没有意义) 请注意,对于变量d,我们保证已重写抽象方法(否

我当时正在做一种研发工作,对抽象类的概念感到困惑

我所知道的抽象类可能包含具体方法,也可能包含虚拟方法。它可能包含也可能不包含抽象方法,它可能包含字段并限制实例的直接创建


但是,我们可以在一个简单的基类中实现所有这些(添加虚拟方法会起到很大作用,因为一个基类包含虚拟方法,而虚拟方法不包含实现,并且重写与抽象方法相同)。那么为什么我们需要一个抽象类,尽管接口支持多继承和事件?

主要区别在于编译器不允许您实例化抽象类,而您可以实例化基类(这可能没有意义)

请注意,对于变量
d
,我们保证已重写抽象方法(否则
DerivedType
类将出现编译器错误)

既然你评论了很多困惑,我会给你举个例子,让这个概念真正适合我。想象你正在做一个塔防游戏。你有一个塔楼类,每个塔楼都有攻击的能力,所以你制作了一个抽象的塔楼类,如下所示:

abstract class Tower
{
    abstract void Attack();
}
现在我可以制作几个塔类:

class FlameTower : Tower
{
    override void Attack()
    {
        //Shoot flames at everyone
    }
}

class IceTower : Tower
{
    override void Attack()
    {
        //Shoot ice everywhere
    }
}
现在,如果您想声明一个塔的列表,您可以写:

 List<Tower> towerList = new List<Tower>();
 towerList.Add(new FireTower());
 towerList.Add(new IceTower());
而且每个类都保证实现了攻击,因为它被标记为抽象的,如果它们不这样做,则将是编译错误。现在所有这些都可以通过基类完成,除了基类允许:

 towerList.Add(new Tower());

现在,当它试图调用对
newtower()
的攻击时,它将命中一个空白的抽象方法,这不是我们想要的。因此,为了禁止将某个对象声明为通用塔,我们将该类抽象化,这样我们就知道所有对象都有自己的
攻击定义,并且它会做一些事情。

一个简单的答案可能是:-

基类有自己的方法实现,这些实现可以在继承类中使用/添加。可以实例化基类

抽象类具有类方法的声明。任何继承抽象类的类都必须实现它的abstract方法,或者成为抽象类。不能实例化抽象类

示例:-

public abstract class A
{
   public void Method1()
   {
     //method code
   }

   public abstract void Method2();

   public virtual void Method3()
   {
    //method code for class A, when class A calls Method3, this code is executed
   }
}

public class B : A
{
   public override void Method2()
   {
     //this must be implemented here to use it
   }

   public override void Method3()
   {
     //method code for class B, when class B calls Method3, this code is executed
     //or, if you choose not to override this method, the compiler will use the code in class A
   }
}

类B仍然可以使用类A中的Method1,因为它是继承的。如果类A是抽象的,那么所有的方法都将像Method2一样声明,并且必须在类B中实现才能使用。

有些类在现实世界中根本不存在,因此在概念上应该标记为
抽象的。例如,考虑<代码>抽象类动物< /代码>。现实世界中没有“动物”这类东西。取而代之的是一些具体类型的动物,如狗、猫等

但是我们可以在一个简单的基类中实现所有这些

不,你不能。您不能有一个具有抽象方法的非抽象类(定义了签名但没有给出实现的方法,从而强制派生类提供实现)

抽象类的存在是为了提供实现方法和抽象方法的组合

您可以尝试通过使用不做任何事情的具体实现来避免使用
抽象类,但它有许多缺点:

  • 它不会强制调用方重写实现
  • 它给人的印象是,该类型和那些方法特别有效,而实际上它们并不有效。通过添加抽象方法和类型的特性,可以防止不完整类型被未意识到它不完整的人意外使用
  • 它为子类提供了一个明确的契约,关于它们需要提供什么功能,以及基类的哪些方法正在工作,但可以选择性地进行扩展

在没有抽象的世界中也考虑非空洞方法。它们需要抛出(即

NotImplementedException
)或返回无效值(即
null
)。这可能比什么都不做的方法糟糕得多。

这里的优势是什么?我们可以像abstractclass ab=新的derviced类()这样间接地进行操作@peter,但是您有一个派生类而不是抽象类(因此您可以确保抽象方法有一个定义)伟大的代码示例。这与我在上面与动物讨论的内容类似。例如,如果
抽象类Animal
具有函数
public abstract void eatStuff()
,则可以保证
动物的每个具体实例都知道如何自己进食。@music\u coder是的,我一直讨厌动物示例,因为我很难想象为动物编写代码,我喜欢举一些与制作游戏相关的例子,因为每个人都喜欢制作游戏!如果基类包含虚拟方法,那么这是可能的。我对我的问题做了一些修改,如果基类包含虚拟方法,那么会是什么样的基类?有什么区别吗,忘记抽象方法的名称。因为虚拟方法我们也可以将其作为抽象方法并重写it@peter你不能忘记他们。它们是唯一的关键区别。如果你忘记了它们,你将一无所获,但你不能忘记它们,因为它们是抽象类的要点。如果你没有任何抽象方法,那么你就不需要抽象类。我想要的是虚拟方法,我们也可以把它作为抽象方法,没有任何实现和重写it@peter这不会强制调用方重写实现,并且给人的印象是
 towerList.Add(new Tower());
public abstract class A
{
   public void Method1()
   {
     //method code
   }

   public abstract void Method2();

   public virtual void Method3()
   {
    //method code for class A, when class A calls Method3, this code is executed
   }
}

public class B : A
{
   public override void Method2()
   {
     //this must be implemented here to use it
   }

   public override void Method3()
   {
     //method code for class B, when class B calls Method3, this code is executed
     //or, if you choose not to override this method, the compiler will use the code in class A
   }
}