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

Ответ

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

  • 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 вашего класса.

Ответ 18+ 🔞

А, ну вот, опять про эти ваши модификаторы доступа. Слушай, это же элементарно, Ватсон! Представь себе класс — это как твоя квартира, блядь.

  • public — это типа парадная дверь нараспашку, коврик «Добро пожаловать» и табличка «Заходите все, кому не лень». Любой прохожий с улицы может зайти и потрогать твой диван. Ну, если ты, конечно, разрешил. В коде это значит — видно и доступно отовсюду, где виден сам класс. Хули тут думать.

  • private — это твой сейф в спальне, куда ты прячешь свои грязные носки, паспорт и бутылку коньяка «на чёрный день». Никто, сука, кроме тебя самого, туда залезть не может. Ни жена, ни дети, ни сосед Вася. Только ты, внутри своего же класса. Это святое, это основа основ, ёпта! Все поля по умолчанию должны быть такими, чтобы всякие левые методы не шарились где не надо.

  • protected — а это уже интереснее. Это как общий семейный шкаф в прихожей. Ты (базовый класс) можешь туда лазить, и твои дети (классы-наследники) тоже могут. А вот соседям или просто гостям (другим классам извне) — хуй. Доступа нет. Удобно, когда хочешь дать наследникам какую-то силу, но спрятать её от всего остального мира.

Смотри, как это в деле, на примере банковского счёта, который я на коленке написал:

public class BankAccount // Это наш главный чувак, базовый класс
{
    // Номер счёта — public. Висит на фасаде, всем видно. Пусть знают.
    public string AccountNumber { get; set; }

    // А вот комиссия за операцию — private, в сейфе. Это наше внутреннее дело, нахуй никому не светим.
    private decimal _transactionFee = 0.01m;

    // Баланс — protected. Самому себе доступно, и наследникам — можно. А посторонним — иди на хуй.
    protected decimal Balance { get; set; }

    public void Deposit(decimal amount) // Публичный метод — типа банкомат с купюроприёмником.
    {
        // А внутри метода мы как боги: и к балансу доступ есть, и к приватной комиссии.
        Balance += amount - (amount * _transactionFee);
    }
}

public class SavingsAccount : BankAccount // Это наш наследничек, накопительный счёт.
{
    public void ApplyInterest() // Капает процент, всё такое.
    {
        // Так, баланс-то protected — значит, можем его тут трогать! Окей.
        Balance *= 1.05m;

        // А вот тут обосрёшься на ровном месте! _transactionFee — он private у родителя.
        // Для тебя, наследника, его как бы не существует. Компилятор скажет: «Иди на хуй, не вижу такого поля».
        // decimal fee = _transactionFee; // Эта строка не скомпилируется, пиздец.
    }
}

public class Program
{
    static void Main()
    {
        var account = new SavingsAccount();
        account.AccountNumber = "12345"; // Ну да, public же, хуле нет-то.
        // account.Balance = 1000; // А вот тут — облом. Protected, чувак.
        // Из Main, который вообще не в иерархии наследования, баланс не виден. Как отче наш.
    }
}

Итог, коротко и ясно, как ёбнуть гвоздь:
По умолчанию всё делай private — меньше проблем.
Если планируешь, что наследники будут что-то кастомизировать — кидай им protected, как кость.
А public — это твоё лицо, API, контракт с внешним миром. Делай его максимально узким и понятным, а то потом охуеешь отлаживать, кто и где всё поломал. Всё, вопрос закрыт.