Scénarios du monde réel pour les méthodes protégées

14

Aujourd'hui, j'ai remarqué que je n'utilise pratiquement pas de protectedméthodes dans le code C ++, car je ressens rarement le besoin d'appeler des méthodes non publiques d'un parent. J'utilise protégé en Java dans le modèle de méthode de modèle, mais comme vous pouvez remplacer les méthodes privées en C ++, je n'en ai pas besoin non protectedplus.

Alors, quels sont certains scénarios du monde réel où je voudrais utiliser des protectedméthodes en code C ++?

(Notez que je n'aime pas trop l'héritage d'implémentation en général, cela pourrait expliquer beaucoup de choses ...)

fredoverflow
la source

Réponses:

12

Voici un exemple

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

protected:
  ~Base() { }
};

Utilisé comme classe de base non polymorphe. Mais les utilisateurs ne seront pas autorisés à y faire appel delete baseptr;car le destructeur est inaccessible. Puisqu'il n'a pas de destructeur virtuel, permettre aux gens de le faire serait un comportement indéfini. Voir "Virtuality" par Herb.

Johannes Schaub - litb
la source
1
Que se passe-t-il avec vous? Pourquoi cela a-t-il été rejeté? C'est parfaitement raisonnable. Si vous ne le comprenez pas, veuillez demander. Si vous pensez que c'est mal, veuillez expliquer. Nous sommes ici pour apprendre de vos idées.
sbi
Pourquoi -1? C'est la première chose à laquelle j'ai pensé.
GManNickG
1
Les constructeurs et les destructeurs sont les seules utilisations que j'ai vues. Notez que gcc émet toujours un avertissement que le destructeur n'est pas virtuel sur celui-ci.
Matthieu M.
+1 J'utilise également la méthode protégée pour appliquer quelques conseils de livres: avoir une interface publique avec des fonctions virtuelles protégées, au lieu de fonctions virtuelles publiques.
Klaim
3

Un exemple que j'utilise fréquemment est que dans la classe de base de ma hiérarchie d'objet, j'aurai un enregistreur protégé. Toutes mes classes de base auront besoin d'accéder au Logger, mais il n'y a aucune raison de le rendre accessible au public.

De plus, si vous utilisez le modèle Template et que vous avez une méthode pré ou post-exécution sur la classe de base, vous souhaiterez peut-être appeler l'implémentation de base à partir de la méthode prioritaire. Si la base est uniquement privée (et peut toujours être écrasée en C ++), vous ne pourrez pas appeler l'implémentation de base à partir de la méthode prioritaire.

bryanatkinson
la source
1
N'est-ce pas le modèle de modèle de ne pas avoir à appeler les méthodes de classe de base ???
sbi
Point pris, mais je ne dirais pas que c'est «tout» de ne pas avoir à appeler les méthodes de classe de base. Dans de nombreuses situations, j'ai des hiérarchies d'objets implémentant le modèle de modèle qui ont plusieurs niveaux, chacun ajoutant légèrement plus de fonctionnalités / vérifications. Dans ces cas, une méthode protégée serait nécessaire.
bryanatkinson
1

Juste un exemple que j'ai utilisé dans le passé. Les méthodes protégées sont idéales pour fournir des fonctions spécifiques à l'implémentation, tout en permettant également à la classe de base de suivre correctement les choses. Considérons une classe de base qui fournit une fonction d'initialisation remplaçable, mais doit également avoir un état pour déterminer si elle est initialisée:

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

Tout va bien ici. Sauf lorsqu'une classe dérivée ne prend pas la peine d'appeler setInitialized()le fait que tout le monde peut l'appeler (nous pourrions le faire protégé ici, et une autre raison d'utiliser des méthodes protégées!). Je préfère de loin une classe qui utilise des membres virtuels protégés:

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

Dans notre nouvelle classe, toute l'initialisation est toujours déléguée à la classe dérivée. À condition qu'une exception ait été levée, nous maintenons le contrat "cette classe est initialisée" qui, selon notre méthode, se produira.

Moo-Juice
la source
0

Comme de nombreuses autres fonctionnalités, protectedvous permet de rompre l'encapsulation dans une certaine mesure. Rompre les concepts OO purs se fait généralement pour plusieurs raisons

  1. obtenir de meilleures performances (penser inline),
  2. rendre le code plus facile à comprendre et, ironiquement,
  3. meilleure encapsulation ( friendvous permet de restreindre l'accès aux membres de la classe à quelques amis)

et protectedn'est qu'un des outils de cette boîte. Vous pouvez l'utiliser si vous souhaitez donner aux classes dérivées un accès à certaines parties d'une classe qui doivent être cachées au grand public.

Un cas où je l'ai utilisé est de créer tous les constructeurs d'une classe protected, ce qui rend cette classe abstraite (vous ne pouvez pas l'instancier sauf en tant que sous-objet d'un objet d'une classe dérivée).

sbi
la source
0

C'était peut-être un mauvais design, mais je l'avais pour quelque chose comme ça:

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

Les classes dérivées, dans update(), pourraient déclencher le signal en appelant trigger_signal(). Mais comme c'est tout ce qu'ils devraient pouvoir faire avec le signal, le signal lui-même est resté privé. La fonction de déclenchement a été rendue protégée car seule la classe dérivée doit pouvoir la déclencher, pas du tout.

GManNickG
la source
0

"Méthodes publiques": une classe peut le faire. "Méthodes protégées": comment une classe peut le faire. "Méthodes privées": comment une classe peut faire cela, mais "je suis paranoïaque et je ne veux pas que quiconque sache comment je le fais".

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

Ainsi, un nouveau cuisinier (développeur) arrive dans votre restaurant de restauration rapide. Vous l'enseignez, vous vendez des burguers (méthodes publiques), comment préparer les burguers (méthodes protégées), mais gardez pour vous la recette secrète "brevetée".

umlcat
la source