Ответ
В C# наследование распространяется не на все члены класса. Производный класс не наследует следующие члены базового:
- Конструкторы и деструкторы (финализаторы): Каждый класс должен определять свои собственные. Однако производный класс обязан вызывать конструктор базового класса (явно через
base()или неявно), что обеспечивает корректную инициализацию унаследованной части объекта. - Закрытые (
private) члены: Поля, методы, свойства и события с модификаторомprivate. Они невидимы для производного класса, хотя физически присутствуют в составе объекта. - Члены, помеченные модификатором
new: Если в базовом классе член объявлен сnew, он не считается частью полиморфной иерархии для производных классов.
Важное уточнение: Статические члены (static) не наследуются в смысле полиморфизма экземпляров, но они доступны производному классу через имя базового класса. Их нельзя переопределить (override), но можно скрыть (new).
Пример, демонстрирующий правила:
public class BaseClass
{
private int _privateField = 10; // 1. Не наследуется (недоступен в Derived).
public int PublicField = 20; // Наследуется.
public static int StaticField = 30; // 2. Не наследуется полиморфно, но доступен как BaseClass.StaticField.
public BaseClass(int value) { } // 3. Конструктор не наследуется.
private void PrivateMethod() { } // 1. Не наследуется.
}
public class DerivedClass : BaseClass
{
// Обязан вызвать конструктор базового класса.
public DerivedClass() : base(100) { }
// Свой собственный конструктор.
public DerivedClass(string name) : base(200) { }
public void Demonstrate()
{
PublicField = 50; // OK: унаследованное публичное поле.
// _privateField = 5; // ОШИБКА КОМПИЛЯЦИИ: private член недоступен.
int value = BaseClass.StaticField; // OK: доступ через имя базового типа.
// int value2 = StaticField; // ОШИБКА (если не объявить новый StaticField в Derived).
}
}
Это обеспечивает инкапсуляцию (private члены) и четкое разделение ответственности (конструкторы).
Ответ 18+ 🔞
А, ну это классика, блядь! Сидишь такой, думаешь — наследование, о, круто, щас всё от базы переедет, как по маслу. Ан хуй там! В C# не всё так просто, как кажется, ёпта.
Смотри, есть члены класса, которые нахер не переезжают в твой производный класс, хоть ты тресни. Вот они, засранцы:
-
Конструкторы и деструкторы (ну или финализаторы, кому как удобнее). Это, блядь, как отпечатки пальцев — у каждого класса свои собственные. Но вот прикол: твой производный класс обязан, сука, вызвать конструктор базы. Или явно через
base(), или неявно, если там дефолтный. Иначе объект не соберётся, как надо — унаследованная часть останется неинициализированной, и будет тебе пиздец, а не программа. -
Закрытые (
private) члены. Ну это вообще пиздец очевидно, но многие тупят. Поля, методы, свойства сprivate— они для производного класса как стена китайская, невидимы нахер. Хотя физически-то они в объекте есть, да. Но тронуть их не можешь — инкапсуляция, мать её. -
Члены, помеченные
new. Если в базе что-то объявили сnew, то для полиморфной иерархии это как бы и не считается. Ты его, конечно, увидишь, но переопределить (override) не сможешь — только скрыть своим собственнымnew. Короче, геморрой, а не фича.
А вот ещё нюанс, блядь, важный: статические члены (static). Их в смысле полиморфизма экземпляров не наследуют, ёпта. Но! Доступ к ним есть — через имя базового класса. Переопределить (override) их нельзя, но зато можно скрыть своим new, если очень приспичило.
Смотри пример, чтобы вообще всё стало ясно, как божий день:
public class BaseClass
{
private int _privateField = 10; // 1. Не наследуется — в Derived не увидишь, хоть глаз выколи.
public int PublicField = 20; // А вот это — да, наследуется, пользуйся на здоровье.
public static int StaticField = 30; // 2. Статика — не наследуется полиморфно, но BaseClass.StaticField — пожалуйста.
public BaseClass(int value) { } // 3. Конструктор — не наследуется, свой пиши.
private void PrivateMethod() { } // 1. И это private — тоже не наследуется, естественно.
}
public class DerivedClass : BaseClass
{
// ОБЯЗАН вызвать конструктор базы, иначе компилятор наебнёт.
public DerivedClass() : base(100) { }
// Можешь и свои конструкторы городить, главное — базу вызови.
public DerivedClass(string name) : base(200) { }
public void Demonstrate()
{
PublicField = 50; // Окей, унаследованное публичное поле — делай что хочешь.
// _privateField = 5; // ОШИБКА КОМПИЛЯЦИИ! Private член — нихуя не доступен.
int value = BaseClass.StaticField; // Нормально, обращайся через имя базового типа.
// int value2 = StaticField; // ОШИБКА! (если только сам не объявишь StaticField в Derived).
}
}
Вот так вот, блядь. Это всё не просто так — чтобы инкапсуляцию (private члены) не сломать и чтобы каждый класс сам за свою инициализацию отвечал (конструкторы). А то бы был полный бардак, ёпта.