【问题标题】:What is the difference between a simple base class and abstract class?简单基类和抽象类有什么区别?
【发布时间】:2013-09-24 21:57:35
【问题描述】:

我在做某种研发,对抽象类的概念感到困惑。

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

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

【问题讨论】:

  • StackOverflow 标签“abstract-class”和“base-class”也有很好的参考定义,以区分抽象类和基类,即使抽象类没有任何抽象方法.... ............抽象类是不能被实例化的类。它们的存在是为了为几个具体的类提供通用的功能和接口规范。......在面向对象编程中,基类是其他类继承的基类。例如,一个子类Male 和另一个子类Female 可能都继承自基类Human

标签: c# .net abstract-class base-class


【解决方案1】:

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

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

抽象类有类方法的声明。任何继承抽象类的类都必须实现它的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 中实现才能使用。

【讨论】:

  • @peter:- 这只是一个例子。虽然我明白你指的是什么;)
【解决方案2】:

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

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

BaseType b = new BaseType(); //OK

注意变量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());

然后遍历它们并让它们都攻击:

 foreach (Tower t in towerList)
 {
     t.Attack();
 }

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

 towerList.Add(new Tower());

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

【讨论】:

  • 这里有什么优势?我们可以像 abstractclass ab= new derviced class(); 那样间接地做;
  • @peter 但是你有一个派生类而不是一个抽象类(所以你可以确保抽象方法有一个定义)
  • 很棒的代码示例。这类似于我上面讨论的动物。例如,如果abstract class Animal 具有函数public abstract void eatStuff(),则可以保证Animal 的每个具体实例都知道如何自己吃饭。
  • @musical_coder 是的,我一直讨厌动物的例子,因为我很难想象为动物编写代码,我喜欢给出与制作游戏相关的例子,因为每个人都喜欢制作游戏!
【解决方案3】:

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

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

抽象类存在,因此它们可以提供实现方法和抽象方法的组合。

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

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

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

【讨论】:

  • 那么什么是带有虚拟方法的基类?有什么区别,忘记命名抽象方法。因为虚拟方法也可以将它作为抽象方法并覆盖它
  • @peter 你不能忘记他们。它们是唯一的关键区别。 如果你忘记了它们,你将一无所有,但你不能忘记它们,因为它们是抽象类的。如果你没有有任何抽象方法,那么你就不需要抽象类。
  • 我想要的是虚拟方法,我们也可以把它作为没有任何实现的抽象方法并覆盖它
  • @peter 这不会强制调用者重写实现,并且给人的印象是类型和那些方法特别有效,而实际上它们不是。通过添加抽象方法和类型的特性,您可以防止未意识到不完整类型的人意外使用不完整类型。它还为子类提供了关于它们需要提供什么功能的明确约定。特别要考虑非 void 方法,其中在没有 abstract 的世界中的基本实现需要抛出或返回无效值。
  • 这是很好的评论,你能用这个评论编辑你的答案
【解决方案4】:

有些类在现实世界中根本不存在,因此在概念上应标记为abstract。例如,考虑abstract class Animal。现实世界中没有“动物”这样的东西。取而代之的是具体类型的动物,例如DogCat等。

【讨论】:

  • 那么这可以通过基类包含虚拟方法来实现,我对我的问题做了一些修改
猜你喜欢
  • 2015-09-26
  • 2010-10-10
  • 2011-01-24
  • 1970-01-01
  • 2010-12-27
  • 2010-11-13
  • 2013-02-17
相关资源
最近更新 更多