Какие члены базового класса не наследуются производным классом в C#?

Ответ

В C# наследование распространяется не на все члены класса. Производный класс не наследует следующие члены базового:

  1. Конструкторы и деструкторы (финализаторы): Каждый класс должен определять свои собственные. Однако производный класс обязан вызывать конструктор базового класса (явно через base() или неявно), что обеспечивает корректную инициализацию унаследованной части объекта.
  2. Закрытые (private) члены: Поля, методы, свойства и события с модификатором private. Они невидимы для производного класса, хотя физически присутствуют в составе объекта.
  3. Члены, помеченные модификатором 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# не всё так просто, как кажется, ёпта.

Смотри, есть члены класса, которые нахер не переезжают в твой производный класс, хоть ты тресни. Вот они, засранцы:

  1. Конструкторы и деструкторы (ну или финализаторы, кому как удобнее). Это, блядь, как отпечатки пальцев — у каждого класса свои собственные. Но вот прикол: твой производный класс обязан, сука, вызвать конструктор базы. Или явно через base(), или неявно, если там дефолтный. Иначе объект не соберётся, как надо — унаследованная часть останется неинициализированной, и будет тебе пиздец, а не программа.

  2. Закрытые (private) члены. Ну это вообще пиздец очевидно, но многие тупят. Поля, методы, свойства с private — они для производного класса как стена китайская, невидимы нахер. Хотя физически-то они в объекте есть, да. Но тронуть их не можешь — инкапсуляция, мать её.

  3. Члены, помеченные 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 члены) не сломать и чтобы каждый класс сам за свою инициализацию отвечал (конструкторы). А то бы был полный бардак, ёпта.