Почему C # допускает абстрактный класс без абстрактных членов? - PullRequest
20 голосов
/ 08 июня 2010

Спецификация 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 # допускает абстрактный класс только с конкретными членами?

Следует отметить, что я уже знаком с предполагаемой функциональностью абстрактных типов и членов.

Ответы [ 9 ]

23 голосов
/ 08 июня 2010

Возможно, хорошим примером является общий базовый класс, который предоставляет общие свойства и, возможно, другие члены для производных классов, но не представляет конкретный объект.Например:

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

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

У всех питомцев есть имена, но само животное - это абстрактное понятие.Экземпляр домашнего животного должен быть собакой или каким-либо другим животным.

Разница в том, что вместо предоставления метода, который должен быть переопределен разработчиками, базовый класс объявляет, что все домашние животные состоятминимум Name свойство.

11 голосов
/ 08 июня 2010

Идея состоит в том, чтобы заставить разработчика унаследовать класс, поскольку он призван обеспечить только основу для предположительно более специализированной реализации.Таким образом, базовый класс, не имеющий абстрактных членов, может содержать только основные методы и свойства, которые можно использовать как основу для расширения.

Например:

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()
    {
    }
}
8 голосов
/ 08 июня 2010

Я думаю, что несколько более точное представление вашего вопроса будет таким: Почему C # допускает абстрактный класс с только конкретными членами?

Ответ: Нет веской причины не делать этого. Возможно, у кого-то есть какая-то организационная структура, в которой ему нравится иметь неинстантируемый класс наверху, даже если класс ниже него просто наследует и ничего не добавляет. Нет веской причины не поддерживать это.

3 голосов
/ 08 июня 2010

Вы сказали это - потому что вы не можете создать это экземпляр;это должен быть только шаблон.

Это не «действительно конкретный класс», если вы объявляете его абстрактным.Это доступно вам как выбор дизайна.

Этот выбор дизайна может иметь отношение к созданию сущностей, которые (рискуют смешаться с терминологией) абстракций объектов реального мира, ис удобочитаемостью.Вы можете объявить параметры типа Car, но не хотите, чтобы объекты объявлялись как Car - вы хотите, чтобы каждый объект типа Car создавался как Truck, Sedan, Coupe или Roadster.Тот факт, что Car не не требует наследников для добавления реализации, не умаляет его значения как абстрактной версии его наследников, для которых сам экземпляр не может быть создан.

1 голос
/ 08 июня 2010

Что касается использования, использование abstract в объявлении класса, но без абстрактных членов, равнозначно использованию класса public, но с использованием protected в его конструкторах.И то и другое вынуждает класс быть извлеченным для его создания.

Однако, что касается самодокументируемого кода, пометив класс abstract, он сообщает другим, что этот класс никогда не долженсоздается самостоятельно, даже если у него нет virtual или abstract членов.Принимая во внимание, что защита конструкторов не делает такого утверждения.

1 голос
/ 08 июня 2010

Аннотация означает предоставление абстракции поведения.Например, Автомобиль - это абстрактная форма.У него нет экземпляра в реальном мире, но мы можем сказать, что Автомобиль обладает ускоряющим поведением.В частности, Ford Ikon - это автомобиль, а Yamaha FZ - это автомобиль.Оба они имеют ускоряющее поведение.

Если вы сейчас сделаете это в форме класса.Транспортное средство является абстрактным классом с методом ускорения.Хотя вы можете / не можете предоставить какой-либо абстрактный метод.Но бизнес-необходимость заключается в том, что автомобиль не должен быть создан.Следовательно, вы делаете это абстрактным.Два других класса - Ikon и FZ являются конкретными классами, производными от класса Vehicle.У этих двоих будут свои свойства и поведение.

0 голосов
/ 08 июня 2010

Я вижу абстрактные классы, служащие двум основным целям:

  • Неполный класс, который должен быть специализированным, чтобы предоставлять конкретную услугу. Здесь абстрактные члены будут необязательными . Класс будет предоставлять некоторые службы, которые могут использовать дочерние классы, и может определять абстрактные члены, которые он использует для предоставления своих услуг, как в Pattern Method Pattern . Этот тип абстрактного класса предназначен для создания иерархии наследования .

  • Класс, который предоставляет только статические служебные методы . В этом случае абстрактные члены вообще не имеют смысла. C # поддерживает это понятие со статическими классами , они неявно абстрактны и запечатаны. Этого также можно добиться с помощью закрытого класса с частным конструктором.

0 голосов
/ 08 июня 2010

Вот потенциальная причина:

Слой Supertype

Это не редкость для всех объектов в слое, чтобы иметь методы, которые вы не хочу дублировать на протяжении система. Вы можете переместить все это поведение в общий слой Supertype.

- Мартин Фаулер

Нет никаких причин для запрещать иметь только конкретные методы в абстрактном классе - это просто менее распространено. Layer Supertype - это тот случай, когда это может иметь смысл.

0 голосов
/ 08 июня 2010

Компилятор не мешает реализации-логике, но в вашем случае я бы просто пропустил abstract ?! Кстати, некоторые методы могут быть реализованы с помощью { throw Exception("must inherit"); }, и компилятор не может различить полностью реализованные классы и функции, включая только throw .

...