21

C# 规范第 10.1.1.1 节指出:

允许(但不是必需)抽象类包含抽象成员。

这允许我创建这样的类:

public abstract class A
{
    public void Main() 
    {
        // it's full of logic!
    }
}

甚至更好:

public abstract class A
{
    public virtual void Main() { }
}

public abstract class B : A
{
    public override sealed void Main()
    {
        // it's full of logic!
    }
}

这确实是一个具体的类;就无法实例化它而言,它只是抽象的。例如,如果我想执行其中的逻辑,B.Main()我必须首先获取 B 的实例,这是不可能的。

如果继承者实际上不必提供实现,那为什么称它为抽象呢?

换句话说,为什么 C# 允许只有具体成员的抽象类?

我应该提到我已经熟悉抽象类型和成员的预期功能。

4

9 回答 9

23

也许一个很好的例子是一个公共基类,它为派生类提供共享属性和其他成员,但不表示具体对象。例如:

public abstract class Pet
{
    public string Name{get;set;}
}

public class Dog : Pet
{
    public void Bark(){ ... }
}

所有的宠物都有名字,但宠物本身是一个抽象的概念。宠物的实例必须是狗或其他某种动物。

这里的区别在于,基类没有提供应该由实现者重写的方法,而是声明所有宠物至少由一个Name属性组成。

于 2010-06-08T18:31:00.520 回答
11

这个想法是强制实现者从类派生,因为它旨在仅为可能更专业的实现提供基础。因此,基类虽然没有任何抽象成员,但可能只包含核心方法和可用作扩展基础的属性。

例如:

public abstract class FourLeggedAnimal
{

    public void Walk()
    {
        // most 4 legged animals walk the same (silly example, but it works)
    }

    public void Chew()
    {

    }
}

public class Dog : FourLeggedAnimal
{
    public void Bark()
    {
    }
}

public class Cat : FourLeggedAnimal
{
    public void Purr()
    {
    }
}
于 2010-06-08T18:03:22.703 回答
8

我认为您的问题的更准确的表示是:为什么 C# 允许只有具体成员的抽象类?

答案是:没有充分的理由不这样做。也许有人有一些组织结构,他们喜欢在顶部有一个不可实例化的类,即使它下面的一个类只是继承并没有添加任何内容。没有充分的理由支持这一点。

于 2010-06-08T18:21:56.870 回答
3

你说了——因为你不能实例化它;它只是一个模板。

如果您将其声明为抽象,则它不是“真正的具体类”。您可以将其作为设计选择。

这种设计选择可能与创建实体(存在混淆术语的风险)现实世界对象的抽象以及可读性有关。您可能希望声明 type 的参数Car,但不希望将对象声明为Car- 您希望将每个 type 的对象Car实例化为TruckSedanCoupeRoadster不需要继承者添加实现的事实Car并没有减损其作为其自身不能被实例化的继承者的抽象版本的价值。

于 2010-06-08T18:38:23.537 回答
1

抽象意味着提供行为的抽象。例如 Vehicle 是一种抽象形式。它没有任何真实世界的实例,但我们可以说 Vehicle 具有加速行为。更具体地说,福特 Ikon 是一辆汽车,而雅马哈 FZ 是一辆汽车。这两者都有加速行为。

如果您现在以课堂形式进行此操作。Vehicle 是具有 Acceleration 方法的抽象类。虽然您可能/可能不提供任何抽象方法。但是业务需求是 Vehicle 不应该被实例化。因此,您将其抽象化。其他两个类 - Ikon 和 FZ 是派生自 Vehicle 类的具体类。这两个将有自己的属性和行为。

于 2010-06-08T18:39:36.080 回答
1

关于用法,abstract在类声明上使用但没有抽象成员与拥有类publicprotected在其构造函数上使用相同。两者都强制派生类以便对其进行实例化。

然而,就自文档化代码而言,通过标记类abstract,它会告诉其他人这个类永远不会被自己实例化,即使它没有virtualabstract成员。而保护构造函数则没有这样的断言。

于 2010-06-08T19:19:05.460 回答
0

编译器不会阻止实现逻辑,但在你的情况下,我会简单地省略abstract?!顺便说一句,可以使用某些方法来实现,{ throw Exception("must inherit"); }编译器无法区分完全实现的类和函数,仅包括throw

于 2010-06-08T18:17:06.007 回答
0

这是一个潜在的原因:

层超类型

一个层中的所有对象都有您不想在整个系统中复制的方法并不少见。您可以将所有这些行为移动到一个通用的图层超类型中。

——马丁·福勒

没有理由阻止抽象类中只有具体的方法——它不太常见。层超类型是一个可能有意义的情况。

于 2010-06-08T18:53:53.637 回答
0

我看到抽象类有两个主要目的:

  • 一个不完整的类,必须专门提供一些具体的服务。在这里,抽象成员是可选的。该类将提供一些子类可以使用的服务,并且可以定义它用来提供其服务的抽象成员,就像在模板方法模式中一样。这种类型的抽象类旨在创建继承层次结构

  • 只提供静态实用方法的类。在这种情况下,抽象成员根本没有意义。C# 用静态类支持这个概念,它们是隐式抽象和密封的。这也可以通过带有私有构造函数的密封类来实现。

于 2010-06-08T19:19:00.673 回答