Escenarios del mundo real para métodos protegidos.

14

Hoy noté que básicamente nunca uso protectedmétodos en código C ++, porque rara vez siento la necesidad de llamar a métodos no públicos de un padre. Utilizo protegido en Java en el patrón de método de plantilla, pero como puede anular métodos privados en C ++, tampoco lo necesito protected.

Entonces, ¿cuáles son algunos escenarios del mundo real en los que me gustaría usar protectedmétodos en código C ++?

(Tenga en cuenta que no soy muy aficionado a la herencia de implementación en general, eso podría explicar mucho ...)

flujo libre
fuente

Respuestas:

12

Aquí hay un ejemplo

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

protected:
  ~Base() { }
};

Usado como una clase base no polimórfica. Pero a los usuarios no se les permitirá llamar delete baseptr;porque el destructor es inaccesible. Como no tiene un destructor virtual, permitir que las personas hagan eso sería un comportamiento indefinido. Ver "Virtualidad" de Herb.

Johannes Schaub - litb
fuente
1
¿Qué pasa con ustedes chicos? ¿Por qué se rechazó esto? Es perfectamente razonable. Si no lo entiende, por favor pregunte. Si siente que está mal, explique. Estamos aquí para aprender de sus ideas.
sbi
¿Por qué -1? Esto es lo primero que pensé.
GManNickG
1
Constructores y Destructores son los únicos usos que he visto. Tenga en cuenta que gcc todavía emite una advertencia de que el destructor no es virtual en este caso.
Matthieu M.
+1 También utilizo un método protegido para aplicar algunos consejos de libros: tener una interfaz pública con funciones virtuales protegidas, en lugar de funciones virtuales públicas.
Klaim
3

Un ejemplo que uso con frecuencia es que en la Clase base de mi Jerarquía de objetos tendré un Logger protegido. Todas mis clases básicas necesitarán acceso al registrador, pero no hay ninguna razón para que sea públicamente accesible.

Además, si está utilizando el patrón de Plantilla y tiene un método de ejecución previa o posterior en la clase base, puede llamar a la implementación base desde el método de anulación. Si la base solo es privada (y aún se puede sobrescribir en C ++), no podrá llamar a la implementación base desde el método de anulación.

Bryanatkinson
fuente
1
¿No se trata el patrón de plantilla de no tener que llamar a métodos de clase base?
sbi
Punto tomado, pero no diría que es 'todo' sobre no tener que llamar a métodos de clase base. En muchas situaciones, tengo jerarquías de objetos que implementan el patrón de plantilla que tiene múltiples niveles, cada uno de los cuales agrega un poco más de funcionalidad / verificación. En estos casos, sería necesario un método protegido.
bryanatkinson
1

Solo un ejemplo que he usado en el pasado. Los métodos protegidos son excelentes para proporcionar funciones específicas de implementación, al tiempo que permiten que la clase base realice un seguimiento adecuado de las cosas. Considere una clase base que proporciona una función de inicialización reemplazable, pero también debe tener un estado para determinar si se inicializa:

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

Todo está bien y bien aquí. Excepto cuando una clase derivada no se molesta en llamar, sobre setInitialized()todo el hecho de que cualquiera puede llamarla (¡podríamos proteger esto aquí, y otra razón para usar métodos protegidos!). Prefiero una clase que haga uso de miembros virtuales protegidos:

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

En nuestra nueva clase, toda la inicialización todavía se delega a la clase derivada. Siempre que se haya lanzado una excepción, mantenemos el contrato "esta clase se inicializa" que nuestro método dice que sucederá.

Jugo De Moo
fuente
0

Como muchas otras características, le protectedpermite romper la encapsulación en cierta medida. Romper los conceptos de OO puro generalmente se hace por varias razones

  1. lograr un mejor rendimiento (pensar inline),
  2. haciendo que el código sea más fácil de entender e, irónicamente,
  3. mejor encapsulación (le friendpermite restringir el acceso a los miembros de la clase a unos pocos amigos)

y protectedes solo una de las herramientas en esa caja. Puede usarlo si desea dar acceso a clases derivadas a algunas partes de una clase que deberían estar ocultas para el público en general.

Un caso en el que lo he usado es hacer que todos los constructores de una clase protected, básicamente, hagan que esa clase sea abstracta (no se puede crear una instancia, excepto como un subobjeto de un objeto de una clase derivada).

sbi
fuente
0

Quizás fue un mal diseño, pero lo tuve para algo como esto:

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

Las clases derivadas, en update(), podrían activar la señal llamando trigger_signal(). Pero como eso es todo lo que deberían poder hacer con la señal, la señal en sí se dejó en privado. La función de activación se protegió porque solo la clase derivada debería poder activarla, nada en absoluto.

GManNickG
fuente
0

"Métodos públicos": una clase puede hacer esto. "Métodos protegidos": cómo una clase puede hacer esto. "Métodos privados": cómo una clase puede hacer esto, pero "soy paranoico y no quiero que nadie sepa cómo lo hago".

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

Entonces, un nuevo cocinero (desarrollador) llega a su restaurante de comida rápida. Lo enseñas, vendes hamburguesas (métodos públicos), cómo preparar las hamburguesas (métodos protegidos), pero guarda la salsa de receta secreta "patentada" para ti.

umlcat
fuente