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

Виртуальные методы и свойства

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

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

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

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

Например, рассмотрим следующие классы:


class Person
{
	public string Name { get; set; }
	public Person(string name)
	{
		Name = name;
	}
	public virtual void Print()
	{
		Console.WriteLine(Name);
	}
}
class Employee : Person
{
	public string Company { get; set; }
	public Employee(string name, string company) : base(name)
	{
		Company = company;
	}
}

Здесь класс Person представляет человека. Класс Employee наследуется от Person и представляет сотруднника предприятия. Этот класс кроме унаследованного свойства Name имеет еще одно свойство - Company.

Чтобы сделать метод Print доступным для переопределения, этот метод определен с модификатором virtual. Поэтому мы можем переопределить этот метод, но можем и не переопределять. Допустим, нас устраивает реализация метода из базового класса. В этом случае объекты Employee будут использовать реализацию метода Print из класса Person:


Person bob = new Person("Bob");
bob.Print(); // вызов метода Print из класса Person

Employee tom = new Employee("Tom", "Microsoft");
tom.Print(); // вызов метода Print из класса Person

Консольный вывод:


Bob
Tom

Но также можем переопределить виртуальный метод. Для этого в классе-наследнике определяется метод с модификатором override, который имеет то же самое имя и набор параметров:


class Employee : Person
{
	public string Company { get; set; }
	public Employee(string name, string company)
		: base(name)
	{
		Company = company;
	}
	public override void Print()
	{
		Console.WriteLine($"{Name} работает в {Company}");
	}
}

Возьмем те же самые объекты:


Person bob = new Person("Bob");
bob.Print(); // вызов метода Print из класса Person

Employee tom = new Employee("Tom", "Microsoft");
tom.Print(); // вызов метода Print из класса Employee

Консольный вывод:


Bob
Tom работает в Microsoft

Виртуальные методы базового класса определяют интерфейс всей иерархии, то есть в любом производном классе, который не является прямым наследником от базового класса, можно переопределить виртуальные методы. Например, мы можем определить класс Manager, который будет производным от Employee, и в нем также переопределить метод Print.

При переопределении виртуальных методов следует учитывать ряд ограничений:

  • Виртуальный и переопределенный методы должны иметь один и тот же модификатор доступа. То есть если виртуальный метод определен с помощью модификатора public, то и переопредленный метод также должен иметь модификатор public.

  • Нельзя переопределить или объявить виртуальным статический метод.

Ключевое слово base

Кроме конструкторов, мы можем обратиться с помощью ключевого слова base к другим членам базового класса. В нашем случае вызов base.Print(); будет обращением к методу Print() в классе Person:


class Employee : Person
{
    public string Company { get; set; }
 
    public Employee(string name, string company)
			:base(name)
    {
        Company = company;
    }
 
    public override void Print()
    {
        base.Print();
        Console.WriteLine($"работает в {Company}");
    }
}

Переопределение свойств

Также как и методы, можно переопределять свойства:


class Person
{
	int age = 1;
	public virtual int Age
	{
		get => age;
		set{ if(value > 0 && value < 110) age = value; }
	}
	public string Name { get; set; }
	public Person(string name)
    {
        Name = name;
    }
	public virtual void Print() => Console.WriteLine(Name);
}
class Employee : Person
{
	public override int Age
	{
		get => base.Age;
		set { if (value > 17 && value < 110) base.Age = value; }
	}
	public string Company { get; set; }
	public Employee(string name, string company)
		: base(name)
	{
		Company = company;
		base.Age = 18; // возраст для работников по умолчанию
	}
}

В данном случае в классе Person определено виртуальное свойство Age, которое устанавливает значение, если оно больше 0 и меньше 110. В классе Employee это свойство переопределено - возраст работника должен быть не меньше 18.


Person bob = new Person("Bob");
Console.WriteLine(bob.Age); // 1

Employee tom = new Employee("Tom", "Microsoft");
Console.WriteLine(tom.Age); // 18
tom.Age = 22;
Console.WriteLine(tom.Age); // 22
tom.Age = 12;
Console.WriteLine(tom.Age); // 22

Запрет переопределения методов

Также можно запретить переопределение методов и свойств. В этом случае их надо объявлять с модификатором sealed:


class Employee : Person
{
    public string Company { get; set; }
 
    public Employee(string name, string company)
                : base(name)
	{
		Company = company;
	}

	public override sealed void Print()
	{
		Console.WriteLine($"{Name} работает в {Company}");
	}
}

При создании методов с модификатором sealed надо учитывать, что sealed применяется в паре с override, то есть только в переопределяемых методах.

И в этом случае мы не сможем переопределить метод Print в классе, унаследованном от Employee.

Дополнительные материалы

Проверь себя

📋 Тест по теме «Виртуальные методы и свойства» Тест по теме

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

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

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

class _____
{
	public string Name { get; set; }
	public Person(string name)
	{
		Name = name;
	}
	public virtual void Print()
	{
		Console.WriteLine(Name);
	}
}
class Employee : Person
{
	public string Company { get; set; }
	public Employee(string name, string company) : base(name)
	{
		Company = company;
	}
}
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (2)
+10 XP

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

Person _____ = new Person("Bob");
bob.Print(); // вызов метода Print из класса Person

Employee tom = new Employee("Tom", "Microsoft");
tom.Print(); // вызов метода Print из класса Person
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (3)
+10 XP

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

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

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

class Employee : Person
{
	public string Company { _____; set; }
	public Employee(string name, string company)
		: base(name)
	{
		Company = company;
	}
	public override void Print()
	{
		Console.WriteLine($"{Name} работает в {Company}");
	}
}
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (5)
+10 XP

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

Person bob = new Person("_____");
bob.Print(); // вызов метода Print из класса Person

Employee tom = new Employee("Tom", "Microsoft");
tom.Print(); // вызов метода Print из класса Employee
Войдите, чтобы отправить решение
Среднее Ручная проверка Восстановите код по памяти (1)
+20 XP

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

class Person
{
	public string Name { get; set; }
	public Person(string name)
	{
		Name = name;
	}
	public virtual void Print()
	{
		Console._____(Name);
	}
}
class _____ : Person
{
	public string Company { get; set; }
	public Employee(string name, string company) : base(name)
	{
		Company = company;
	}
}
Войдите, чтобы отправить решение
Среднее Ручная проверка Восстановите код по памяти (2)
+20 XP

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

_____ bob = new Person("Bob");
bob.Print(); // вызов метода Print из класса Person

_____ tom = new Employee("Tom", "Microsoft");
tom.Print(); // вызов метода Print из класса Person
Войдите, чтобы отправить решение
Среднее Ручная проверка Расставьте строки кода в правильном порядке
+20 XP

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

Person bob = new Person("Bob");
Employee tom = new Employee("Tom", "Microsoft");
bob.Print(); // вызов метода Print из класса Person
tom.Print(); // вызов метода Print из класса Person
Войдите, чтобы отправить решение
Сложное Ручная проверка Объясните и модифицируйте пример из урока «Виртуальные методы и свойства»
+30 XP

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

class Person
{
	public string Name { get; set; }
	public Person(string name)
	{
		Name = name;
	}
	public virtual void Print()
	{
		Console.WriteLine(Name);
	}
}
class Employee : Person
{
	public string Company { get; set; }
	public Employee(string name, string company) : base(name)
	{
		Company = company;
	}
}
Войдите, чтобы отправить решение
Сложное Ручная проверка Найдите потенциальную проблему в коде урока «Виртуальные методы и свойства»
+30 XP

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

Person bob = new Person("Bob");
bob.Print(); // вызов метода Print из класса Person

Employee tom = new Employee("Tom", "Microsoft");
tom.Print(); // вызов метода Print из класса Person
Войдите, чтобы отправить решение
Мини-проект Ручная проверка Мини-проект по теме «Виртуальные методы и свойства»
+50 XP

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

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

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

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

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

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