Reale Szenarien für geschützte Methoden

14

Heute ist mir aufgefallen, dass ich protectedim C ++ - Code grundsätzlich keine Methoden verwende, da ich selten das Bedürfnis habe, nicht öffentliche Methoden eines übergeordneten Elements aufzurufen. Ich verwende protected in Java im Muster der Template-Methode, aber da Sie private Methoden in C ++ überschreiben können, brauche ich das auch nicht protected.

Was sind also einige reale Szenarien, in denen ich protectedMethoden in C ++ - Code verwenden möchte ?

(Beachten Sie, dass ich die Vererbung von Implementierungen im Allgemeinen nicht besonders mag, das könnte eine Menge erklären ...)

fredoverflow
quelle

Antworten:

12

Hier ist ein Beispiel

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

protected:
  ~Base() { }
};

Wird als nicht polymorphe Basisklasse verwendet. Benutzer dürfen jedoch nicht darauf zugreifen, delete baseptr;da auf den Destruktor nicht zugegriffen werden kann. Da es keinen virtuellen Destruktor gibt, wäre es undefiniertes Verhalten, wenn man dies zulässt. Siehe "Virtualität" von Herb.

Johannes Schaub - litb
quelle
1
Was ist mit euch los? Warum wurde das abgelehnt? Es ist vollkommen vernünftig. Wenn Sie es nicht verstehen, fragen Sie bitte. Wenn Sie das Gefühl haben, dass es falsch ist, erklären Sie es bitte. Wir sind hier, um aus Ihren Erkenntnissen zu lernen.
sbi
Warum -1? Dies ist das erste, woran ich dachte.
GManNickG
1
Konstruktoren und Destruktoren sind die einzigen Verwendungen, die ich gesehen habe. Beachten Sie, dass gcc weiterhin eine Warnung ausgibt, dass der Destruktor in diesem Fall nicht virtuell ist.
Matthieu M.
+1 Ich verwende auch eine geschützte Methode, um Ratschläge zu einigen Büchern anzuwenden: eine öffentliche Schnittstelle mit geschützten virtuellen Funktionen anstelle von öffentlichen virtuellen Funktionen.
Klaim
3

Ein Beispiel, das ich häufig verwende, ist, dass ich in der Basisklasse meiner Objekthierarchie einen geschützten Logger haben werde. Alle meine Basisklassen benötigen Zugriff auf den Logger, aber es gibt keinen Grund, diesen öffentlich zugänglich zu machen.

Wenn Sie das Vorlagenmuster verwenden und über eine Pre- oder Post-Execute-Methode für die Basisklasse verfügen, möchten Sie möglicherweise die Basisimplementierung über die überschreibende Methode aufrufen. Wenn die Basis nur privat ist (und weiterhin in C ++ überschrieben werden kann), können Sie die Basisimplementierung nicht über die überschreibende Methode aufrufen.

Bryanatkinson
quelle
1
Geht es beim Template-Muster nicht darum, keine Basisklassenmethoden aufrufen zu müssen?
sbi
Der Punkt ist genommen, aber ich würde nicht sagen, dass es darum geht, keine Basisklassenmethoden aufrufen zu müssen. In vielen Situationen habe ich Objekthierarchien, die das Vorlagenmuster implementieren und mehrere Ebenen haben, von denen jede etwas mehr Funktionalität / Überprüfungen hinzufügt. In diesen Fällen wäre eine geschützte Methode erforderlich.
Bryanatkinson
1

Nur ein Beispiel, das ich in der Vergangenheit verwendet habe. Geschützte Methoden eignen sich hervorragend für die Bereitstellung implementierungsspezifischer Funktionen und ermöglichen es der Basisklasse, die Dinge ordnungsgemäß zu verfolgen. Stellen Sie sich eine Basisklasse vor, die eine überschreibbare Initialisierungsfunktion bietet, aber auch einen Status haben muss, um festzustellen, ob sie initialisiert wurde:

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

Hier ist alles gut und schön. Außer wenn sich eine abgeleitete Klasse nicht darum kümmert, setInitialized()nicht zuletzt die Tatsache aufzurufen , dass jeder sie aufrufen kann (wir könnten dies hier als geschützt erklären und einen weiteren Grund, geschützte Methoden zu verwenden!). Ich bevorzuge eine Klasse, die virtuelle geschützte Mitglieder verwendet:

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

In unserer neuen Klasse wird die gesamte Initialisierung weiterhin an die abgeleitete Klasse delegiert. Vorausgesetzt, es wurde eine Ausnahme ausgelöst, wird der Vertrag "Diese Klasse ist initialisiert" beibehalten, der nach unserer Methode ausgeführt wird.

Moo-Juice
quelle
0

Wie bei vielen anderen Funktionen protectedkönnen Sie die Kapselung in gewissem Umfang aufheben. Das Aufbrechen der reinen OO-Konzepte erfolgt normalerweise aus mehreren Gründen

  1. bessere Leistung erzielen (denken inline),
  2. Code verständlicher machen und ironischerweise
  3. Bessere Kapselung ( friendermöglicht es Ihnen, den Zugriff auf Klassenmitglieder auf wenige Freunde zu beschränken)

und protectedist nur eines der Tools in dieser Box. Sie können es verwenden, wenn Sie abgeleiteten Klassen Zugriff auf einige Teile einer Klasse gewähren möchten, die für die breite Öffentlichkeit verborgen werden sollen.

Ein Fall, in dem ich es verwendet habe, besteht darin, alle Konstruktoren einer Klasse zu protectedabstrahieren (Sie können es nur als Unterobjekt eines Objekts einer abgeleiteten Klasse instanziieren).

sbi
quelle
0

Vielleicht war es schlechtes Design, aber ich hatte es für so etwas:

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

Abgeleitete Klassen können update()das Signal durch Aufrufen auslösen trigger_signal(). Aber weil das alles ist, was sie mit dem Signal tun sollten, wurde das Signal selbst privat gelassen. Die Trigger-Funktion wurde geschützt, da nur die abgeleitete Klasse in der Lage sein sollte, sie auszulösen, und überhaupt nichts.

GManNickG
quelle
0

"Öffentliche Methoden": Eine Klasse kann dies tun. "Geschützte Methoden": Wie kann eine Klasse dies tun? "Private Methoden": Wie eine Klasse dies tun kann, aber "Ich bin paranoid und möchte nicht, dass jemand weiß, wie ich es tue".

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

Also kommt ein neuer Koch (Entwickler) in Ihr Fast-Food-Restaurant. Sie lehren es, Sie verkaufen Burger (öffentliche Methoden), wie man die Burger zubereitet (geschützte Methoden), aber behalten die "patentierte" Geheimrezeptsoße für sich.

umlcat
quelle