Реальні сценарії для захищених методів


14

Сьогодні я помітив, що я в основному ніколи не використовую protectedметоди в коді С ++, тому що рідко відчуваю потребу викликати некритичні методи батьків. Я використовую захищені в Java схему методу шаблону, але оскільки ви можете перекрити приватні методи в C ++, мені це також не потрібно protected.

Отже, які реальні сценарії, де я хотів би використовувати protectedметоди в коді C ++?

(Зауважте, що я не надто люблю успадкування впровадження в цілому, що може пояснити багато ...)

Відповіді:


12

Ось приклад

class Base {
public:
  // other members ...

protected:
  ~Base() { }
};

Застосовується як неполіморфний базовий клас. Але користувачі заборонять дзвонити delete baseptr;на нього, оскільки деструктор недоступний. Оскільки він не має віртуального деструктора, дозволяти людям робити це було б невизначеною поведінкою. Дивіться "Віртуальність" від Трави.


1
Що з вами, хлопці? Чому це було знято? Це цілком розумно. Якщо ви цього не розумієте, запитайте. Якщо ви відчуваєте, що це неправильно, поясніть, будь ласка. Ми тут, щоб дізнатись із ваших поглядів.
— sbi

Чому -1? Це перше, що я придумав.
— GManNickG

1
Конструктори та деструктори - це єдине використання, яке я бачив. Зауважте, що gcc все ще надсилає попередження про те, що деструктор у цьому невіртуальний.
— Матьє М.

+1 Я також використовую захищений метод, щоб застосувати деякі поради щодо книг: мати публічний інтерфейс із захищеними віртуальними функціями замість публічних віртуальних функцій.
— Клаїм

3

Одним із прикладів, якими я часто користуюсь, є те, що в базовому класі мого об’єкта Ієрархія матиме захищений реєстратор. Усі мої базові класи потребуватимуть доступу до Logger, але немає жодних підстав робити це загальнодоступним.

Крім того, якщо ви використовуєте шаблон шаблону, і у вас є метод попереднього чи після виконання базового класу, ви можете зателефонувати на реалізацію бази від методу переосмислення. Якщо база є лише приватною (і все ще може бути перезаписана на C ++), ви не зможете викликати реалізацію бази за допомогою методу переосмислення.


1
Хіба шаблон шаблону не полягає в тому, що не потрібно викликати методи базового класу ???
— sbi

Точка прийнята, але я б не сказав, що це "все" про те, що не потрібно викликати методи базового класу. У багатьох ситуаціях у мене є ієрархії об'єктів, що реалізують шаблон шаблону, який має кілька рівнів, кожен з яких додає трохи більше функціональності / перевірок. У цих випадках необхідний захищений метод.
— bryanatkinson

1

Просто приклад, який я використовував у минулому. Захищені методи чудово підходять для забезпечення функцій, що залежать від впровадження, а також дозволяють базовому класу правильно відстежувати речі. Розглянемо базовий клас, який забезпечує функцію ініціалізації, що перезаписується, але також повинен мати стан для визначення, чи ініціалізовано:

class Base
{
private:
    bool m_bInitialized;
public:
    virtual void Initialize() = 0;

    void setInitialized() { m_bInitialized = true; };
    bool isInitialized() const { return m_bInitialized; };
}; // eo class Base

Тут все добре і добре. За винятком випадків, коли похідний клас не намагається називати setInitialized()не в останню чергу тим, що хтось може його викликати (ми могли б зробити це захищеним тут, і ще одна причина використовувати захищені методи!). Я дуже віддаю перевагу класу, який використовує віртуальних захищених членів:

class Base
{
private: 
    bool m_bInitialized;

protected:
    virtual void InitializeImpl() = 0;

public:

    void Initialize()
    {
        InitializeImpl();
        m_bInitialized = true;
    }; // eo Initialize

    bool isInitialized() const { return m_bInitialized; };
}; // eo class Base

У нашому новому класі вся ініціалізація все ще делегована похідному класу. За умови виключення виключення, ми підтримуємо контракт "цей клас ініціалізований", який, за нашим методом, каже, відбудеться.


0

Як і багато інших функцій, protectedдозволяє розбити інкапсуляцію до деякого розширення. Порушення чистих концепцій ОО зазвичай робиться з кількох причин

  1. досягнення кращих показників (подумайте inline ),
  2. полегшує розуміння коду, і, як не дивно,
  3. краща інкапсуляція ( friendдозволяє обмежити доступ членів класу кількома друзями)

і protectedце лише один із інструментів цього вікна. Ви можете використовувати його, якщо ви хочете надати похідним класам доступ до деяких частин класу, які слід приховати від широкої громадськості.

Один з випадків, коли я його використовував, - це зробити всі конструктори класу protected, в основному роблячи цей клас абстрактним (ви не можете його інстанціювати, за винятком суб'єкта об'єкта похідного класу).


0

Можливо, це був поганий дизайн, але я мав його на щось подібне:

// much simplified, of course
class input_device // base class
{
public:
    virtual ~input_device() {}

    // normally would be private with public caller, etc.
    virtual void update() = 0; 

    template <typename Func>
    void register_callback(Func func)
    {
        mButtonPressSignal.connect(func);
    }

protected:
    void trigger_signal(unsigned button)
    {
        mButtonPressSignal(button);
    }

private:
    boost::signals2::signal<void(unsigned)> mButtonPressSignal;
};

Отримані класи, в update(), можуть викликати сигнал за допомогою виклику trigger_signal(). Але оскільки це все, що вони повинні мати змогу зробити із сигналом, сам сигнал залишився приватним. Функція тригера була захищена, оскільки тільки похідний клас повинен бути здатний запускати її, а не що-небудь взагалі.


0

"Публічні методи": Клас може це зробити. "Захищені методи": як клас може це зробити. "Приватні методи": як клас може це зробити, але "я параноїк і не хочу, щоб хто-небудь знав, як я це роблю".

// burguers.hpp

class BurguerClass {
  private: void addSecretRecipeSauce();  

  protected: virtual void addBread();  
  protected: virtual void addSalad();  
  protected: virtual void addMeat();
  protected: virtual void addExtraIngredients();

  public: virtual void makeBurguer();  
}

class CheeseBurguerClass: public BurguerClass {
  protected: override void addBread();  
  protected: override void addSalad();  
  protected: override void addMeat();
  protected: override void addExtraIngredients();

  protected: virtual void addCheese();

  public: override void makeBurguer();
}

class RanchStyleBurguerClass: public BurguerClass {
  protected: override void addBread();  
  protected: override void addSalad();  
  protected: override void addMeat();
  protected: override void addExtraIngredients();

  public: override void makeBurguer();
}

class EastCoastVegetarianStyleBurguerClass: public BurguerClass {
  protected: override void addBread();  
  protected: override void addSalad();  
  protected: override void addMeat();
  protected: override void addExtraIngredients();

  public: override void makeBurguer();
}

Отже, новий кухар (розробник) приїжджає у ваш ресторан швидкого харчування. Ви цього вчите, ви продаєте бургури (публічні методи), як готувати боргу (захищені методи), але зберігайте «запатентований» секретний рецепт соусу для себе.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.