В чем разница между модификаторами доступа public, private и protected?

«В чем разница между модификаторами доступа public, private и protected?» — вопрос из категории ООП, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Модификаторы доступа определяют область видимости членов класса (полей, свойств, методов), реализуя принцип инкапсуляции.

  • public: Доступ разрешен из любого места в коде, где виден сам класс. Это самый открытый уровень доступа.
  • private: Доступ разрешен только внутри того же класса, где член объявлен. Это самый строгий и наиболее часто используемый уровень по умолчанию для полей.
  • protected: Доступ разрешен внутри класса, где член объявлен, и внутри любых классов-наследников (производных классов). Извне иерархии наследования доступ закрыт.

Пример на C#:

public class BankAccount // Базовый класс
{
    // Доступно везде (из Main, из других классов)
    public string AccountNumber { get; set; }

    // Доступно только внутри BankAccount. Скрывает внутреннюю логику.
    private decimal _transactionFee = 0.01m;

    // Доступно в BankAccount и его наследниках (например, SavingsAccount).
    protected decimal Balance { get; set; }

    public void Deposit(decimal amount)
    {
        // Доступ ко всем членам внутри класса:
        Balance += amount - (amount * _transactionFee);
    }
}

public class SavingsAccount : BankAccount // Производный класс
{
    public void ApplyInterest()
    {
        // OK: Protected член доступен в наследнике.
        Balance *= 1.05m;

        // Ошибка компиляции: Private член базового класса недоступен.
        // decimal fee = _transactionFee;
    }
}

public class Program
{
    static void Main()
    {
        var account = new SavingsAccount();
        account.AccountNumber = "12345"; // OK: Public
        // account.Balance = 1000; // Ошибка: Protected недоступен извне иерархии.
    }
}

Практическое правило: Сделайте члены private по умолчанию. Используйте protected, чтобы предоставить контролируемый доступ для расширения функциональности в наследниках. Используйте public для определения четкого API вашего класса.