Полное руководство по языку программирования С# 14 и платформе .NET 10 / Объектно-ориентированное программирование

Абстрактные классы и члены классов

Начальный ⏱ 7 мин чтения 👁 2 🕓 обновлено 11.08.2026

Абстрактные классы

Кроме обычных классов в C# есть абстрактные классы. Зачем они нужны? Классы обычно представляют некий план определенного рода объектов или сущностей. Например, мы можем определить класс Car для преставления машин или класс Person для представления людей, вложив в эти классы соответствующие свойства, поля, методы, которые будут описывать данные объекты. Однако некоторые сущности, которые мы хотим выразить с помощью языка программирования, могут не иметь конкретного воплощения. Например, в реальности не существует геометрической фигуры как таковой. Есть круг, прямоугольник, квадрат, но просто фигуры нет. Однако же и круг, и прямоугольник имеют что-то общее и являются фигурами. И для описания подобных сущностей, которые не имеют конкретного воплощения, предназначены абстрактные классы.

Абстрактный класс похож на обычный класс. Он также может иметь переменные, методы, конструкторы, свойства. Единственное, что при определении абстрактных классов используется ключевое слово abstract. Например, определим абстрактный класс, который представляет некое транспортное средство:


abstract class Transport
{
	public void Move()
    {
		Console.WriteLine("Транспортное средство движется");
    }
}

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

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

Transport tesla = new Transport();

Тем не менее абстрактные классы полезны для описания некоторого общего функционала, который могут наследовать и использовать производные классы:


Transport car = new Car();
Transport ship = new Ship();
Transport aircraft = new Aircraft();

car.Move();
ship.Move();
aircraft.Move();
abstract class Transport
{
	public void Move()
    {
		Console.WriteLine("Транспортное средство движется");
    }
}
// класс корабля
class Ship : Transport { }
// класс самолета
class Aircraft : Transport { }
// класс машины
class Car : Transport { }

В данном случае от класса Transport наследуются три класса, которые представляют различные типы транспортных средств. Тем не менее они имеют общую черту - они могут перемещаться с помощью метода Move().

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


Transport car = new Car("машина");
Transport ship = new Ship("корабль");
Transport aircraft = new Aircraft("самолет");

car.Move();			// машина движется
ship.Move();		// корабль движется
aircraft.Move();	// самолет движется
abstract class Transport
{
    public string Name { get; }
    // конструктор абстрактного класса Transport
    public Transport(string name)
    {
		Name = name;
    }
    public void Move() =>Console.WriteLine($"{Name} движется");
}
// класс корабля
class Ship : Transport 
{
	// вызываем конструктор базового класса
	public Ship(string name) : base(name) { }
}
// класс самолета
class Aircraft : Transport
{
	public Aircraft(string name) : base(name) { }
}
// класс машины
class Car : Transport
{
	public Car(string name) : base(name) { }
}

В данном случае в абстрактном классе Transport определен конструктор - с помощью параметра он устанавливает значение свойства Name, которое хранит название транспортного средства. И в этом случае производные классы должны в своих конструкторах вызвать этот конструктор.

Абстрактные члены классов

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

  • Методы

  • Свойства

  • Индексаторы

  • События

Абстрактные члены классов не должны иметь модификатор private. При этом производный класс обязан переопределить и реализовать все абстрактные методы и свойства, которые имеются в базовом абстрактном классе. При переопределении в производном классе такой метод или свойство также объявляются с модификатором override (как и при обычном переопределении виртуальных методов и свойств). Также следует учесть, что если класс имеет хотя бы один абстрактный метод (или абстрактные свойство, индексатор, событие), то этот класс должен быть определен как абстрактный.

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

Абстрактные методы

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


abstract class Transport
{
    public abstract void Move();
}
// класс корабля
class Ship : Transport 
{
	// мы должны реализовать все абстрактные методы и свойства базового класса
	public override void Move()
    {
		Console.WriteLine("Корабль плывет");
    }
}
// класс самолета
class Aircraft : Transport
{
	public override void Move()
	{
		Console.WriteLine("Самолет летит");
	}
}
// класс машины
class Car : Transport
{
	public override void Move()
	{
		Console.WriteLine("Машина едет");
	}
}

Применение классов:


Transport car = new Car();
Transport ship = new Ship();
Transport aircraft = new Aircraft();

car.Move();			// машина едет
ship.Move();		// корабль плывет
aircraft.Move();	// самолет летит

Абстрактные свойства

Следует отметить использование абстрактных свойств. Их определение похоже на определение автосвойств. Например:


abstract class Transport
{
	// абстрактное свойство для хранения скорости
    public abstract int Speed { get; set; }	
}
// класс корабля
class Ship: Transport
{
	int speed;
    public override int Speed 
	{ 
		get => speed; 
		set => speed = value; 
	}
}

class Aircraft : Transport
{
	public override int Speed { get; set; }
}

В классе Transport определено абстрактное свойство Speed, которое должно хранить скорость транспортного средства. Оно похоже на автосвойство, но это не автосвойство. Так как данное свойство не должно иметь реализацию, то оно имеет только пустые блоки get и set. В производных классах мы можем переопределить это свойство, сделав его полноценным свойством (как в классе Ship), либо же сделав его автоматическим (как в классе Aircraft).

Отказ от реализации абстрактных членов

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


Transport tesla = new Auto();
tesla.Move();			// легковая машина едет
abstract class Transport
{
    public abstract void Move();
}
// класс машины
abstract class Car : Transport{}

class Auto: Car
{
	public override void Move()
	{
		Console.WriteLine("легковая машина едет");
	}
}

В данном случае класс Car не реализует абстрактный метод Move базового класса Transport и поэтому также определен как абстрактный. Однако любые неабстрактные классы, производные от Car, все равно должны реализовать все унаследованные абстрактные методы и свойства.

Пример абстрактного класса

Xрестоматийным примером является система геометрических фигур. В реальности не существует геометрической фигуры как таковой. Есть круг, прямоугольник, квадрат, но просто фигуры нет. Однако же и круг, и прямоугольник имеют что-то общее и являются фигурами:


// абстрактный класс фигуры
abstract class Shape
{
    // абстрактный метод для получения периметра
    public abstract double GetPerimeter();
    // абстрактный метод для получения площади
    public abstract double GetArea();
}
// производный класс прямоугольника
class Rectangle : Shape
{
    public float Width { get; set; }
    public float Height { get; set; }

    // переопределение получения периметра
    public override double GetPerimeter() => Width * 2 + Height * 2;
    // переопрелеление получения площади
    public override double GetArea() => Width * Height;
}
// производный класс окружности
class Circle : Shape
{
	public double Radius { get; set; }

	// переопределение получения периметра
	public override double GetPerimeter() => Radius * 2 * 3.14;
	// переопрелеление получения площади
	public override double GetArea() => Radius * Radius * 3.14;
}

Применение классов:


var rectanle = new Rectangle { Width = 20, Height = 20 };
var circle = new Circle { Radius = 200 };
PrintShape(rectanle); // Perimeter: 80   Area: 400
PrintShape(circle);	// Perimeter: 1256  Area: 125600

void PrintShape(Shape shape)
{
	Console.WriteLine($"Perimeter: {shape.GetPerimeter()}  Area: {shape.GetArea()}");
}	
Дополнительные материалы

Проверь себя

📋 Тест по теме «Абстрактные классы и члены классов» Тест по теме

Практические задания

Лёгкое Ручная проверка Заполните пропуск в коде (1)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

_____ class Transport
{
	public void Move()
    {
		Console.WriteLine("Транспортное средство движется");
    }
}
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (2)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

Transport _____ = new Transport();
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (3)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

Transport car = _____ Car();
Transport ship = new Ship();
Transport aircraft = new Aircraft();

car.Move();
ship.Move();
aircraft.Move();
abstract class Transport
{
	public void Move()
    {
		Console.WriteLine("Транспортное средство движется");
    }
}
// класс корабля
class Ship : Transport { }
// класс самолета
class Aircraft : Transport { }
// класс машины
class Car : Transport { }
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (4)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

Transport car = new _____("машина");
Transport ship = new Ship("корабль");
Transport aircraft = new Aircraft("самолет");

car.Move();			// машина движется
ship.Move();		// корабль движется
aircraft.Move();	// самолет движется
abstract class Transport
{
    public string Name { get; }
    // конструктор абстрактного класса Transport
    public Transport(string name)
    {
		Name = name;
    }
    public void Move() =>Console.WriteLine($"{Name} движется");
}
// класс корабля
class Ship : Transport 
{
	// вызываем конструктор базового класса
	public Ship(string name) : base(name) { }
}
// класс самолета
class Aircraft : Transport
{
	public Aircraft(string name) : base(name) { }
}
// класс машины
class Car : Transport
{
	public Car(string name) : base(name) { }
}
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (5)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

abstract class Transport
{
    public abstract void Move();
}
// класс корабля
class _____ : Transport 
{
	// мы должны реализовать все абстрактные методы и свойства базового класса
	public override void Move()
    {
		Console.WriteLine("Корабль плывет");
    }
}
// класс самолета
class Aircraft : Transport
{
	public override void Move()
	{
		Console.WriteLine("Самолет летит");
	}
}
// класс машины
class Car : Transport
{
	public override void Move()
	{
		Console.WriteLine("Машина едет");
	}
}
Войдите, чтобы отправить решение
Среднее Ручная проверка Восстановите код по памяти (1)
+20 XP

В этом фрагменте кода урока пропущены два ключевых элемента. Впишите оба пропущенных значения через запятую в порядке появления (например: x, 5).

_____ class Transport
{
	public void _____()
    {
		Console.WriteLine("Транспортное средство движется");
    }
}
Войдите, чтобы отправить решение
Среднее Ручная проверка Восстановите код по памяти (2)
+20 XP

В этом фрагменте кода урока пропущены два ключевых элемента. Впишите оба пропущенных значения через запятую в порядке появления (например: x, 5).

_____ tesla = _____ Transport();
Войдите, чтобы отправить решение
Среднее Ручная проверка Расставьте строки кода в правильном порядке
+20 XP

Строки кода из примера этого урока перемешаны. Впишите их в правильном порядке, каждую строку — с новой строки.

	public void Move()
}
abstract class Transport
{
		Console.WriteLine("Транспортное средство движется");
    {
    }
Войдите, чтобы отправить решение
Сложное Ручная проверка Объясните и модифицируйте пример из урока «Абстрактные классы и члены классов»
+30 XP

Опишите своими словами, что делает приведённый пример кода из урока «Абстрактные классы и члены классов», и предложите одно осмысленное изменение (например, другое входное значение или дополнительное условие). Приведите итоговый код.

abstract class Transport
{
	public void Move()
    {
		Console.WriteLine("Транспортное средство движется");
    }
}
Войдите, чтобы отправить решение
Сложное Ручная проверка Найдите потенциальную проблему в коде урока «Абстрактные классы и члены классов»
+30 XP

Изучите приведённый фрагмент кода и опишите, при каких входных данных или условиях он может сработать не так, как ожидается (граничный случай, отсутствие проверки и т.п.). Предложите исправленный вариант.

Transport tesla = new Transport();
Войдите, чтобы отправить решение
Мини-проект Ручная проверка Мини-проект по теме «Абстрактные классы и члены классов»
+50 XP

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

Войдите, чтобы отправить решение
Домашнее задание Ручная проверка Домашнее задание по теме «Абстрактные классы и члены классов»
+25 XP

Напишите собственную небольшую программу, применяющую материал темы «Абстрактные классы и члены классов». Используйте не менее одной конструкции, показанной в примерах урока. Прикрепите код решения и краткое описание того, что он делает.

Войдите, чтобы отправить решение

Обсуждение (0)

Войдите, чтобы оставить комментарий.