← Назад к вопросам

Что такое абстрактный класс?

1.6 Junior🔥 222 комментариев
#ООП и паттерны проектирования#Основы C# и .NET

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое абстрактный класс в C#?

Абстрактный класс — это специальный класс в объектно-ориентированном программировании (ООП) на C#, который не может быть инстанцирован (создан напрямую через оператор new). Он служит шаблоном или базовым каркасом для других классов, определяя общую структуру, поведение и контракты, которые должны быть реализованы в производных (наследующих) классах.

Ключевые характеристики абстрактных классов

  1. Невозможность создания экземпляра Абстрактный класс существует только для наследования. Попытка создать его объект приведёт к ошибке компиляции.

    abstract class Animal { }
    
    // Ошибка компиляции: Cannot create an instance of the abstract class 'Animal'
    // Animal animal = new Animal(); 
    
  2. Может содержать абстрактные члены Абстрактные методы, свойства, индексаторы или события не имеют реализации в абстрактном классе и обязаны быть переопределены (реализованы) в производных классах. Они определяют контракт, который должен быть выполнен.

    abstract class Shape
    {
        // Абстрактное свойство (только сигнатура)
        public abstract string Name { get; }
        
        // Абстрактный метод (без тела)
        public abstract double CalculateArea();
        
        // Обычный метод с реализацией
        public void Display()
        {
            Console.WriteLine($"Фигура: {Name}, Площадь: {CalculateArea()}");
        }
    }
    
  3. Может содержать неабстрактные члены с реализацией В отличие от интерфейсов (до C# 8.0), абстрактные классы могут включать полностью реализованные методы, свойства, конструкторы, поля, константы и события. Это позволяет выносить общую логику на уровень базового класса.

    abstract class DatabaseConnector
    {
        protected string ConnectionString; // Поле
        
        // Конструктор абстрактного класса
        protected DatabaseConnector(string connectionString)
        {
            ConnectionString = connectionString;
        }
        
        // Обычный метод с реализацией
        public void Log(string message)
        {
            Console.WriteLine($"[{DateTime.Now}] {message}");
        }
        
        // Абстрактный метод для реализации в наследниках
        public abstract void Connect();
    }
    
  4. Модификатор abstract Класс и его абстрактные члены должны быть явно помечены ключевым словом abstract.

Зачем использовать абстрактные классы? Основные сценарии

  • Реализация общего кода (шаблонный метод). Когда несколько классов имеют общую логику, но отличаются в некоторых ключевых шагах, эту общую логику можно вынести в неабстрактный метод абстрактного класса, а вариативные шаги — в абстрактные, которые будут реализованы потомками.
  • Определение контракта с частичной реализацией. Когда нужно гарантировать, что все наследники реализуют определённые методы (через абстрактные члены), но при этом предоставить им готовую базовую функциональность.
  • Организация иерархии типов. Для создания логической структуры наследования, где базовый класс представляет общую, часто неполную, концепцию (например, Transport, Document, PaymentProcessor).

Пример полного использования

using System;

// Абстрактный класс
abstract class Vehicle
{
    public string Model { get; set; }
    
    // Абстрактный метод - обязан быть реализован
    public abstract void Move();
    
    // Виртуальный метод - может быть переопределён
    public virtual void Stop()
    {
        Console.WriteLine($"{Model} остановился.");
    }
    
    // Обычный метод
    public void DisplayModel()
    {
        Console.WriteLine($"Модель: {Model}");
    }
}

// Конкретный класс-наследник
class Car : Vehicle
{
    // Реализация абстрактного метода
    public override void Move()
    {
        Console.WriteLine($"{Model} едет по дороге.");
    }
    
    // Дополнительно переопределяем виртуальный метод
    public override void Stop()
    {
        Console.WriteLine($"{Model} затормозил с визгом шин.");
    }
}

class Program
{
    static void Main()
    {
        Vehicle myCar = new Car { Model = "Toyota Camry" };
        myCar.DisplayModel(); // Вызов обычного метода из абстрактного класса
        myCar.Move();         // Вызов реализованного абстрактного метода
        myCar.Stop();         // Вызов переопределённого виртуального метода
        
        // Vehicle vehicle = new Vehicle(); // Ошибка!
    }
}

Сравнение с интерфейсами

КритерийАбстрактный классИнтерфейс (до C# 8.0)
ИнстанцированиеНельзяНельзя
Реализация членовМожет содержать как абстрактные, так и реализованные членыСодержал только сигнатуры членов (контракт)
Множественное наследованиеНе поддерживается (класс может наследовать только один абстрактный класс)Поддерживается (класс может реализовать много интерфейсов)
КонструкторыМожет иметьНе может иметь
ПоляМожет иметь поля и константыНе мог иметь (теперь может иметь статические поля)
Модификаторы доступаМожет иметь protected, internal и т.д.Члены по умолчанию public

Важно: Начиная с C# 8.0, интерфейсы получили возможность содержать реализации по умолчанию для методов, статические члены и модификаторы доступа, что частично стёрло границы между ними и абстрактными классами. Однако ключевые различия в виде наличия конструкторов, полей экземпляра и, главное, принципа единого наследования классов против множественной реализации интерфейсов — остаются решающими при выборе.

Итог

Абстрактный класс — это мощный инструмент проектирования, который позволяет создавать стройные иерархии, избегать дублирования кода через вынос общей реализации и чётко определять обязательные для реализации точки расширения в виде абстрактных членов. Его следует выбирать, когда родственные классы имеют явное отношение "является" (is-a) и общую, достаточно объёмную функциональность. Для определения более лёгких контрактов или обеспечения множественного наследования поведения предпочтительнее использовать интерфейсы.