简单基类和抽象类有什么区别?

pet*_*ter 7 .net c# abstract-class base-class

我正在做一种研发,并且对抽象类的概念感到困惑.

我对抽象类的了解是它可能包含具体的方法,它可能包含虚方法.它可能包含也可能不包含抽象方法,它可能包含字段并限制直接创建实例.

但是我们可以在一个简单的基类中实现所有这些(虚拟方法的添加会做很多事情,因为具有虚拟方法的基类不包含实现,并且覆盖与抽象方法相同).那么为什么我们需要一个抽象类,虽然接口支持多重继承和事件?

Ser*_*rvy 14

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

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

存在抽象类,以便它们可以提供已实现方法和抽象方法的组合.

您可以尝试abstract通过使用不执行任何操作的具体实现来避免使用类,但它有许多缺点:

  • 它不会强制调用者覆盖实现.
  • 它给人的印象是,特别是类型和那些方法是有效的,而事实上并非如此.通过添加抽象方法和类型的功能,可以防止意外使用不完整类型的人不会意识到它是不完整的.
  • 它为子类提供了一个明确的契约,即它们需要提供什么功能,而不是基类的哪些方法正在工作,但可以选择扩展.

在没有抽象的世界中也考虑非空方法.他们需要抛出(即NotImplementedException)或返回无效值(即null).这可能比一个什么都不做的方法要糟糕得多.


Kev*_*lia 8

主要的区别是编译器不会让你实例化一个抽象类,而你可以实例化一个基类(这可能没有意义).

AbstractType a = new AbstractType(); //compiler error
AbstractType d = new DerivedType(); //OK

BaseType b = new BaseType(); //OK
Run Code Online (Sandbox Code Playgroud)

请注意,使用变量d我们可以保证抽象方法已被覆盖(否则DerivedType类会产生编译器错误).

既然你正在评论很多混乱,我会给你一个我真正让这个概念点击给我的例子.想象一下,你正在制作塔防游戏.你有一个塔级,每个塔都有攻击能力,所以你要做一个像这样的抽象塔类:

abstract class Tower
{
    abstract void Attack();
}
Run Code Online (Sandbox Code Playgroud)

现在我可以制作几个塔类:

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

class IceTower : Tower
{
    override void Attack()
    {
        //Shoot ice everywhere
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果要声明塔列表,可以写:

 List<Tower> towerList = new List<Tower>();
 towerList.Add(new FireTower());
 towerList.Add(new IceTower());
Run Code Online (Sandbox Code Playgroud)

然后迭代它们并使它们全部受到攻击:

 foreach (Tower t in towerList)
 {
     t.Attack();
 }
Run Code Online (Sandbox Code Playgroud)

并且每个类都保证已经实现了攻击,因为它被标记为抽象,如果它们没有,则会出现编译错误.现在所有这些都可以使用基类来完成,除了基类允许这样做:

 towerList.Add(new Tower());
Run Code Online (Sandbox Code Playgroud)

现在,当它试图调用攻击时,new Tower()它将触及一个空白的抽象方法,这不是我们想要的.因此,为了禁止将某些事物声明为通用塔,我们将类抽象化,然后我们知道所有内容都将拥有它自己的定义Attack并且它会做一些事情.

  • @musical_coder是的我总是讨厌动物的例子,因为我很难想象为动物编写代码,我喜欢举出与制作游戏有关的例子,因为每个人都喜欢制作游戏! (2认同)