Scenariusze rzeczywistych metod chronionych

14

Dzisiaj zauważyłem, że zasadniczo nigdy nie używam protectedmetod w kodzie C ++, ponieważ rzadko czuję potrzebę wywoływania niepublicznych metod rodzica. Używam trybu chronionego w Javie we wzorcu metod szablonów, ale ponieważ możesz zastąpić metody prywatne w C ++, ja też nie potrzebuję protected.

Więc jakie są niektóre scenariusze w świecie rzeczywistym, w których chciałbym zastosować protectedmetody w kodzie C ++?

(Zauważ, że ogólnie nie przepadam za dziedziczeniem implementacji, co może wiele wyjaśniać ...)

fredoverflow
źródło

Odpowiedzi:

12

Oto przykład

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

protected:
  ~Base() { }
};

Używany jako niepolimorficzna klasa bazowa. Ale użytkownicy nie będą mogli do niego zadzwonić delete baseptr;, ponieważ destruktor jest niedostępny. Ponieważ nie ma wirtualnego destruktora, pozwalanie na to byłoby niezdefiniowanym zachowaniem. Zobacz „Wirtualność” autorstwa Herb.

Johannes Schaub - litb
źródło
1
Co jest z wami chłopaki? Dlaczego zostało to zanegowane? To całkowicie rozsądne. Jeśli tego nie rozumiesz, zapytaj. Jeśli uważasz, że to źle, wyjaśnij to. Jesteśmy tutaj, aby uczyć się na podstawie twoich spostrzeżeń.
sbi
Dlaczego -1? To jest pierwsza rzecz, o której myślałem.
GManNickG
1
Konstruktory i Niszczyciele to jedyne zastosowania, jakie widziałem. Zauważ, że gcc nadal emituje ostrzeżenie, że destruktor nie jest wirtualny na tym.
Matthieu M.,
+1 Korzystam również z metody chronionej, aby zastosować się do porad dotyczących książek: mam publiczny interfejs z chronionymi funkcjami wirtualnymi zamiast publicznych funkcji wirtualnych.
Klaim
3

Jednym z często używanych przykładów jest to, że w klasie podstawowej mojego obiektu Hierarchia będę miał chroniony program rejestrujący. Wszystkie moje podstawowe klasy będą potrzebowały dostępu do Logger, ale nie ma powodu, aby udostępnić to publicznie.

Ponadto, jeśli używasz wzorca szablonu i masz metodę wykonywania przed wykonaniem lub po jej wykonaniu w klasie bazowej, możesz wywołać implementację podstawową z metody zastępującej. Jeśli baza jest tylko prywatna (i nadal można ją zastąpić w C ++), nie będzie można wywołać implementacji podstawowej z metody przesłaniającej.

bryanatkinson
źródło
1
Czy wzorzec szablonu nie polega na konieczności wywoływania metod klasy bazowej ???
sbi
Podkreślono, ale nie powiedziałbym, że „wszystko” polega na tym, że nie trzeba wywoływać metod klasy bazowej. W wielu sytuacjach mam hierarchie obiektów implementujące wzorzec szablonu, który ma wiele poziomów, z których każdy dodaje nieco więcej funkcjonalności / kontroli. W takich przypadkach konieczna byłaby metoda chroniona.
bryanatkinson
1

Tylko przykład, z którego korzystałem w przeszłości. Metody chronione świetnie nadają się do zapewniania funkcji specyficznych dla implementacji, a jednocześnie pozwalają klasie podstawowej na właściwe śledzenie rzeczy. Rozważ klasę podstawową, która zapewnia nadrzędną funkcję inicjowania, ale musi również mieć stan, aby określić, czy zainicjowano:

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

Tutaj wszystko jest dobrze. Z wyjątkiem sytuacji, gdy klasa pochodna nie zadaje sobie trudu, aby wywołać setInitialized()nie tylko fakt, że każdy może ją nazwać (moglibyśmy to tutaj zabezpieczyć, i kolejny powód, aby używać chronionych metod!). Wolę klasę, która korzysta z wirtualnych członków chronionych:

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

W naszej nowej klasie cała inicjalizacja jest nadal delegowana do klasy pochodnej. Pod warunkiem, że został zgłoszony wyjątek, utrzymujemy umowę „ta klasa została zainicjowana”, która według naszej metody się wydarzy.

Sok Moo
źródło
0

Podobnie jak wiele innych funkcji, protectedpozwala w pewnym stopniu przerwać enkapsulację. Łamanie czystych koncepcji OO zwykle odbywa się z kilku powodów

  1. osiąganie lepszej wydajności (pomyśl inline),
  2. ułatwiając zrozumienie kodu i, jak na ironię,
  3. lepsza enkapsulacja ( friendpozwala ograniczyć dostęp do członków klasy do kilku znajomych)

i protectedjest tylko jednym z narzędzi w tym pudełku. Możesz go użyć, jeśli chcesz dać klasom pochodnym dostęp do niektórych części klasy, które powinny być ukryte przed ogółem społeczeństwa.

Jednym z przypadków, w których go użyłem, jest stworzenie wszystkich konstruktorów klasy protected, w zasadzie uczynienie tej klasy abstrakcyjną (nie można jej utworzyć, chyba że jest to podobiekt obiektu klasy pochodnej).

sbi
źródło
0

Być może był to zły projekt, ale miałem go do czegoś takiego:

// 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;
};

Klasy pochodne update()mogą wywoływać sygnał przez wywołanie trigger_signal(). Ale ponieważ to wszystko, co powinni zrobić z sygnałem, sam sygnał pozostawiono prywatny. Funkcja wyzwalania została zabezpieczona, ponieważ tylko klasa pochodna powinna być w stanie ją uruchomić, a nie cokolwiek.

GManNickG
źródło
0

„Metody publiczne”: klasa może to zrobić. „Metody chronione”: Jak klasa może to zrobić. „Metody prywatne”: Jak klasa może to zrobić, ale „Jestem paranoikiem i nie chcę, aby ktokolwiek wiedział, jak to robię”.

// 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();
}

Tak więc nowy kucharz (programista) przybywa do restauracji typu fast food. Uczysz go, sprzedajesz burgerów (metody publiczne), jak przygotować burgerów (metody chronione), ale zachowaj dla siebie „opatentowany” tajny sos z przepisu.

umlcat
źródło