В чем разница между простым базовым классом и абстрактным классом?
Я делал своего рода R&D и путаю с концепцией абстрактного класса.
что я знаю об абстрактном классе, так это то, что он может содержать конкретные методы, и он может содержать виртуальные методы. Он может содержать или не содержать абстрактный метод, а также может содержать поля и ограничивать прямое создание экземпляров.
но мы можем достичь всего этого в простом базовом классе (добавление виртуальных методов будет делать много, потому что базовый класс с виртуальным методы, которые не содержат реализации там, и переопределение такое же, как абстрактный метод). Тогда зачем нам нужен абстрактный класс, хотя интерфейс поддерживает множественное наследование и события?
4 ответов
но мы можем достичь всего этого в простом baseclass
Нет, ты не можешь. У вас не может быть неабстрактного класса, который имеет абстрактные методы (методы, где определена подпись, но не задана реализация, таким образом принуждение производные классы для обеспечения реализации).
абстрактные классы exist чтобы они могли предоставить комбинацию реализованных методов и абстрактных методов.
вы можете попытаться чтобы избежать использования abstract
классы с использованием конкретных реализаций, которые просто ничего не делают, но имеют ряд недостатков:
- это не заставляет вызывающего абонента переопределять реализацию.
- создается впечатление, что тип и эти методы, в частности, работают, когда на самом деле они не работают. Добавляя функцию абстрактных методов и типов, вы предотвращаете непреднамеренное использование неполного типа кем-то, кто не понимает, что это незавершенный.
- он предоставляет четкий контракт подклассам относительно того, какую функциональность они должны предоставить, по сравнению с тем, какие методы базового класса работают, но могут быть расширены.
также рассмотрим непустые методы в мире без абстрактного. Им нужно было бы бросить (т. е. NotImplementedException
) или возвращать недопустимое значение (т. е. null
). Это может быть намного хуже, чем метод, который просто ничего не делает.
основное отличие заключается в том, что компилятор не позволит вам создать экземпляр абстрактного класса, в то время как вы можете создать экземпляр базового класса (что может не иметь смысла).
AbstractType a = new AbstractType(); //compiler error
AbstractType d = new DerivedType(); //OK
BaseType b = new BaseType(); //OK
обратите внимание на переменную d
мы гарантируем, что абстрактные методы были переопределены (в противном случае DerivedType
класс будет иметь ошибку компилятора).
поскольку вы комментируете много путаницы, я все равно приведу вам пример, который у меня был, который действительно сделал эту концепцию для меня. Представьте, что вы делаете игру tower defense. У вас есть класс башни, и каждая башня имеет возможность атаковать, поэтому вы делаете абстрактный класс башни следующим образом:
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
и он что-то сделает.
есть некоторые классы, которые просто не существуют в реальном мире, и поэтому должны теоретически быть помечены как abstract
. Рассмотрим, например,abstract class Animal
. В реальном мире нет такого понятия, как "животное". Вместо этого существуют конкретные типы животных, такие как Dog
, Cat
, etc.
один простой ответ может быть:-
базовые классы имеют свои собственные реализации для методов, и эти реализации могут быть использованы/добавлен в унаследованном классе. Можно создать экземпляр базового класса
абстрактные классы имеют объявления для методов класса. Любой класс, наследующий абстрактный класс, должен реализовать его аннотация методы или становится абстрагироваться. Вы не можете создать экземпляр абстрактного класс!--2-->
пример:
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 все еще может использовать Method1 из класса A, потому что он унаследован. И если класс A должен быть абстрактным, то все методы будут объявлены как Method2 и должны быть реализованы в классе B, чтобы его можно было использовать.