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


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.