Ответ
Абстрактный класс в C# — это класс, который служит исключительно в качестве базового для других классов. Его нельзя инстанцировать напрямую с помощью оператора new. Основная цель — определить общий контракт (частичную реализацию) для группы родственных классов.
Ключевые характеристики:
- Нельзя создать экземпляр:
var obj = new AbstractClass();// Ошибка компиляции. - Может содержать абстрактные члены: Методы, свойства, индексаторы или события без реализации. Они помечаются словом
abstractи обязывают производные неабстрактные классы предоставить свою реализацию с помощьюoverride. - Может содержать обычные члены с реализацией: Поля, свойства, методы, конструкторы. Это позволяет вынести общую логику в базовый класс и избежать дублирования кода.
- Может иметь модификатор доступа: Например,
protected abstractметод.
Пример, демонстрирующий общую логику и контракт:
using System;
abstract class Document
{
// Обычное свойство с реализацией (общая логика)
public string Title { get; set; }
public string Author { get; set; }
public DateTime Created { get; } = DateTime.Now;
// Абстрактный метод (контракт, который нужно реализовать)
public abstract void Print();
// Обычный виртуальный метод (общая логика, которую можно переопределить)
public virtual void Save()
{
Console.WriteLine($"Документ '{Title}' сохранён в базовом хранилище.");
}
// Конструктор в абстрактном классе допустим
protected Document(string title, string author)
{
Title = title;
Author = author;
}
}
class PdfDocument : Document
{
public int PageCount { get; set; }
public PdfDocument(string title, string author) : base(title, author) { }
// Реализация абстрактного метода ОБЯЗАТЕЛЬНА
public override void Print()
{
Console.WriteLine($"Печать PDF '{Title}' ({PageCount} стр.).");
}
// Переопределение виртуального метода (опционально)
public override void Save()
{
base.Save(); // Можно вызвать базовую реализацию
Console.WriteLine("Дополнительно: зашифровано и добавлена цифровая подпись.");
}
}
class WordDocument : Document
{
public WordDocument(string title, string author) : base(title, author) { }
public override void Print()
{
Console.WriteLine($"Печать Word-документа '{Title}'.");
}
// Метод Save не переопределён, будет использована реализация из базового класса.
}
// Использование:
Document doc1 = new PdfDocument("Отчёт", "Иван") { PageCount = 10 };
Document doc2 = new WordDocument("Письмо", "Анна");
doc1.Print(); // Печать PDF 'Отчёт' (10 стр.).
doc1.Save(); // Вызовет переопределённый Save из PdfDocument.
doc2.Print(); // Печать Word-документа 'Письмо'.
// doc2.Save(); // Вызовет базовый метод Save из Document.
Когда использовать абстрактный класс, а не интерфейс?
- Абстрактный класс: Когда у производных классов есть чёткая иерархическая связь "is-a" (PdfDocument является Document) и нужно предоставить общую реализацию для части функциональности или состояние (поля).
- Интерфейс: Когда нужно определить контракт, который могут реализовать несвязанные классы. C# 8.0+ позволяет добавлять реализацию по умолчанию и в интерфейсы, но они по-прежнему не могут содержать поля экземпляра.
Ответ 18+ 🔞
Да ты посмотри, что эти умники напридумывали! Абстрактный класс в C# — это как чертёж от инженера, который сам по себе хуй с горы, а не деталь. Взять его в руки и сказать «вот он, готовый агрегат» — нельзя, компилятор морду скривит. Но зато на его основе можно штамповать нормальные, рабочие классы. Ёпта, гениально же!
Что это за зверь такой, по пунктам:
- Создать экземпляр — нихуя.
var obj = new AbstractClass();— это прям билет в ошибку компиляции. Он как дух, материализоваться не может. - Может орать «сделай это сам!». То есть содержать абстрактные члены (методы, свойства) с модным словечком
abstract. И если твой класс от него наследуется и не хочет быть таким же абстрактным придурком, то он ОБЯЗАН эти методы переопределить черезoverride. Иначе — пиздец, не скомпилируется. - Но может и не только орать, а и делать. Может иметь обычные поля, свойства с реализацией, методы и даже конструкторы! Это чтобы общую для всех потомков логику не копировать десять раз, а запихнуть в одного предка. Удобно, чё.
- Может стесняться. Модификаторы доступа ему тоже доступны.
protected abstract— это типа «сынок, этот метод только для семейства, но реализуй его сам».
Смотри, как это в жизни выглядит, на примере документов:
using System;
abstract class Document
{
// Обычные свойства, есть у всех (общая логика)
public string Title { get; set; }
public string Author { get; set; }
public DateTime Created { get; } = DateTime.Now;
// Абстрактный метод (контракт, который нужно реализовать)
public abstract void Print();
// Обычный виртуальный метод (общая логика, которую МОЖНО, но не обязательно, переписать)
public virtual void Save()
{
Console.WriteLine($"Документ '{Title}' сохранён в базовом хранилище.");
}
// Конструктор в абстрактном классе — да, бывает!
protected Document(string title, string author)
{
Title = title;
Author = author;
}
}
class PdfDocument : Document
{
public int PageCount { get; set; }
public PdfDocument(string title, string author) : base(title, author) { }
// Реализация абстрактного метода — ОБЯЗАТЕЛЬНА, иначе ты мудак
public override void Print()
{
Console.WriteLine($"Печать PDF '{Title}' ({PageCount} стр.).");
}
// Переопределение виртуального метода (захотел — сделал)
public override void Save()
{
base.Save(); // Можно и предка позвать, если не упёртый
Console.WriteLine("Дополнительно: зашифровано и добавлена цифровая подпись.");
}
}
class WordDocument : Document
{
public WordDocument(string title, string author) : base(title, author) { }
public override void Print()
{
Console.WriteLine($"Печать Word-документа '{Title}'.");
}
// Метод Save не переопределили — ну и хуй с ним, будет работать стандартный из Document.
}
// Использование:
Document doc1 = new PdfDocument("Отчёт", "Иван") { PageCount = 10 };
Document doc2 = new WordDocument("Письмо", "Анна");
doc1.Print(); // Печать PDF 'Отчёт' (10 стр.).
doc1.Save(); // Вызовет наш навороченный Save из PdfDocument.
doc2.Print(); // Печать Word-документа 'Письмо'.
// doc2.Save(); // А тут вызовется простенький Save из базового Document.
И главный вопрос: когда это использовать, а когда интерфейс?
- Абстрактный класс: Когда у тебя есть чёткая родня по крови. «PDF-документ является документом». И когда этим детям нужно оставить в наследство не только долги (контракты), но и какое-то барахло (поля) и даже готовые рецепты (реализацию методов).
- Интерфейс: Когда нужно определить контракт для кого угодно, даже для абсолютно левых, не родственных классов. Типа «и птица, и самолёт — летают». Да, в новых C# интерфейсы тоже научились иметь реализацию по умолчанию, но поля экземпляра у них всё равно нет, хитрожопые. Так что если нужно состояние — тебе сюда, в абстрактный класс.