Наследование — это один из базовых принципов объектно-ориентированного программирования (ООП). Если попытаться найти более менее полное определение того, что из себя представляет наследование в ООП, то можно встретить, например, такое определение: «Наследование (англ. inheritance) — концепция объектно-ориентированного программирования, согласно которой абстрактный тип данных может наследовать данные и функциональность некоторого существующего типа, способствуя повторному использованию компонентов программного обеспечения.» На первый взгляд, может быть это определение непонятно, но мы с Вами не пишем академическую работу по наследованию в ООП, а учимся использовать механизмы наследования в C#, поэтому рассмотрим этот вопрос на практике.
Простой пример наследования в C#
Чтобы понять суть наследования в C# вернемся к нашему классу Building, который описывает некое здание. Этот класс описывает размеры здания (длину, ширину и высоту) и даже имеет метод расчёта объема и несколько свойств. Мы с этим классом можем работать как угодно в рамках его функциональности. А теперь представим, что нам потребовалось добавить в программу работу не только с некими абстрактными зданиями, а конкретизировать их назначение и свойства, например, нам необходим класс, который будет описывать жилой дом. В этом случае мы можем пойти двумя путями:
- Создать новый класс, описать в нем те же свойства, что и у класса
Buildingи добавить интересующие нас свойства. Несмотря на то, что такой подход вполне сработает, делать так категорически не стоит. О том, почему так не стоит делать мы узнаем ниже, когда ощутим все преимущества наследования в C#. - Наследовать новый класс от класса
Buildingи дописать необходимые свойства и методы.
Итак, назовем наш новый класс House и наследуем его от класса Building. О том, как в Visual Studio C# создать заготовку класса рассказано здесь. Вот как может выглядеть наш новый класс:
internal class House: Building
{
private int windowCount;
public int WindowCount
{
get => windowCount;
set => windowCount = value >= 0 ? value : throw new Exception("Количество окон не может быть меньше нуля");
}
}
В абстрактном виде этот код можно прочитать следующим образом:
класс House унаследован от класса Building начало описания Свойство "Количество окон" конец описания
При этом, обратите внимание на то, что мы не повторялись в описании нового класса и не переносили в него свойства и методы класса Building — они наследовались в новом классе и мы их можем спокойно использовать, например (про упрощенную инициализацию объектов в C# смотри здесь),
using FirstClass;
House house = new House
{
Name ="Жилой дом №1",
Height = 5,
Length = 15,
Width = 20,
WindowCount = 5
};
Console.WriteLine($"Объем дома {house.Volume}");
Console.WriteLine($"Количество окон {house.WindowCount}");
Console.WriteLine($"{house}");
Как видите, мы использовали все возможности класса Building, а также воспользовались новым свойством WindowCount, используя механизмы наследования в C#. В этом-то и кроется вся мощь наследования — мы не повторяемся в коде и наделяем наследников только теми свойствами и методами, которые характерны именно для них, а все общие свойства наследуются автоматически от предков. Вот почему выше я написал, что первый путь создания нового класса в корне не верен и контрпродуктивен во всех смыслах.
Особенности наследования в C#
Как и любой язык программирования, C# обладает своими возможностями и особенностями, которые нам следует помнить и знать. Что касается наследования, то в C# следует помнить, что наследование классов может осуществляться последовательно. Например,
internal class MultiStoreyBuilding: House
{
public int FloorCount { get; set; }
}
здесь для упрощения кода использовано автосвойство FloorCount. Теперь цепочка наследования выглядит следующим образом: Building -> House -> MultiStoreyBuilding и класс MultiStoreyBuilding обладает всеми свойствами как для класса Building, так и для House:
MultiStoreyBuilding house = new MultiStoreyBuilding
{
Name ="Жилой дом №1",
Height = 5,
Length = 15,
Width = 20,
WindowCount = 5,
FloorCount = 5,
};
При этом в C# мы не можем использовать множественное наследование от нескольких классов. Например, следующий код не скомпилируется:
internal class MultiStoreyBuilding: House, Building
{
public int FloorCount { get; set; }
}
и Visual Studio выдаст следующую ошибку:
Для того, чтобы создать класс-наследник нескольких базовых классов нам необходимо идти последовательно, расширяя функциональность нашей программы. При этом, никто не запрещает нам в C# создавать несколько различных наследников от одного базового класса. Например, мы бы могли унаследовать от класса Building сразу несколько классов — частный дом, многоквартирный дом, сарай и так далее.
Такой подход вполне оправдан, интуитивно понятен и довольно широко используется также и в других объектно-ориентированных языках программирования
Итого
Итого, сегодня мы познакомились с тем, что из себя представляет наследование в C# и создали новый класс-наследник. В C# используется последовательный подход к наследованию в рамках которого класс может наследоваться только от одного базового класса.
