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

«Какие члены базового класса не наследуются производным классом в C#?» — вопрос из категории ООП, который задают на 25% собеседований 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 члены) и четкое разделение ответственности (конструкторы).