Ответ
Наследование в .NET реализуется на уровне CLR и поддерживает одиночное наследование реализации (один базовый класс) и множественное наследование интерфейсов.
Базовый синтаксис:
public class Vehicle // Базовый класс
{
public string Manufacturer { get; set; }
public virtual void StartEngine() => Console.WriteLine("Vehicle engine started.");
}
public class Car : Vehicle // Производный класс
{
public int DoorCount { get; set; }
public override void StartEngine() => Console.WriteLine("Car engine roars!");
}
Ключевые аспекты реализации в CLR:
- Единый корень: Все классы неявно наследуются от
System.Object. Это обеспечивает наличие общих методов (ToString(),GetHashCode(),Equals()). - Таблица виртуальных методов (VMT): Каждый тип имеет таблицу, содержащую адреса виртуальных методов. При переопределении (
override) в производном классе соответствующая запись в его VMT заменяется на адрес новой реализации. Это обеспечивает полиморфное поведение. - Вызов конструкторов: Конструкторы не наследуются. При создании объекта производного класса цепочка конструкторов вызывается в порядке от базового к производному.
public class BaseClass
{
public BaseClass() { Console.WriteLine("Base constructor"); }
}
public class DerivedClass : BaseClass
{
// Компилятор неявно вставляет вызов base()
public DerivedClass() { Console.WriteLine("Derived constructor"); }
}
// Вывод: Base constructor -> Derived constructor
- Модификаторы:
sealed— запрещает наследование от класса или дальнейшее переопределение метода.abstract— класс нельзя инстанцировать, он предназначен только для наследования.virtual/override— для полиморфного поведения.new— для сокрытия (hiding) члена базового класса (создаёт новый, независимый член, не участвующий в полиморфизме).
Наследование vs. Композиция: В практике .NET-разработки часто предпочтение отдаётся композиции (включению объектов других классов) над наследованием для повышения гибкости и уменьшения связности кода, следуя принципу "предпочитайте композицию наследованию".