403 Stimmen

Wann sollte man 'friend' in C++ verwenden?

Ich habe mich durch die C++ FAQ und war neugierig auf die friend Erklärung. Ich persönlich habe sie noch nie benutzt, bin aber daran interessiert, diese Sprache zu erforschen.

Was ist ein gutes Beispiel für die Verwendung von friend ?


Wenn ich die FAQ ein wenig länger lese, gefällt mir die Idee des << >> Operatorüberladung und Hinzufügen als Freund dieser Klassen. Ich bin mir jedoch nicht sicher, ob dies nicht gegen die Kapselung verstößt. Wann können diese Ausnahmen innerhalb der Strenge des OOP bleiben?

375voto

Andrew Grant Punkte 57342

Erstens sollte man (IMO) nicht auf Leute hören, die sagen friend ist nicht sinnvoll. Es IST nützlich. In vielen Situationen werden Sie Objekte mit Daten oder Funktionen haben, die nicht öffentlich zugänglich sein sollen. Dies gilt insbesondere für große Codebasen mit vielen Autoren, die mit verschiedenen Bereichen nur oberflächlich vertraut sind.

Es gibt Alternativen zum friend specifier, aber oft sind sie umständlich (cpp-level concrete classes/masked typedefs) oder nicht narrensicher (Kommentare oder Funktionsnamen-Konventionen).

Nun zur Antwort;

En friend Spezifizierer erlaubt der designierten Klasse den Zugriff auf geschützte Daten oder Funktionen innerhalb der Klasse, die die Friend-Anweisung macht. Im unten stehenden Code kann beispielsweise jeder ein Kind nach seinem Namen fragen, aber nur die Mutter und das Kind können den Namen ändern.

Sie können dieses einfache Beispiel weiterführen, indem Sie eine komplexere Klasse wie z. B. ein Fenster betrachten. Ein Fenster wird wahrscheinlich viele Funktions-/Datenelemente haben, die nicht öffentlich zugänglich sein sollten, aber von einer verwandten Klasse wie dem WindowManager benötigt werden.

class Child
{
//Mother class members can access the private parts of class Child.
friend class Mother;

public:

  string name( void );

protected:

  void setName( string newName );
};

175voto

Daemin Punkte 9867

Bei der Arbeit Freunde zum Testen von Code verwenden ausgiebig. Das bedeutet, dass wir den Hauptanwendungscode angemessen kapseln und Informationen verstecken können. Aber wir können auch separaten Testcode haben, der Freunde verwendet, um den internen Zustand und die Daten für Tests zu inspizieren.

Es genügt zu sagen, dass ich das Schlüsselwort "friend" nicht als wesentlichen Bestandteil Ihres Designs verwenden würde.

106voto

En friend hat eine Reihe von guten Verwendungsmöglichkeiten. Hier sind die beiden für mich unmittelbar sichtbaren Verwendungen:

Freund Definition

Die Friend-Definition erlaubt es, eine Funktion im Klassenbereich zu definieren, aber die Funktion wird nicht als Member-Funktion, sondern als freie Funktion des umschließenden Namespaces definiert und ist normalerweise nicht sichtbar, außer für argumentabhängige Lookups. Das macht es besonders nützlich für das Überladen von Operatoren:

namespace utils {
    class f {
    private:
        typedef int int_type;
        int_type value;

    public:
        // let's assume it doesn't only need .value, but some
        // internal stuff.
        friend f operator+(f const& a, f const& b) {
            // name resolution finds names in class-scope. 
            // int_type is visible here.
            return f(a.value + b.value);
        }

        int getValue() const { return value; }
    };
}

int main() {
    utils::f a, b;
    std::cout << (a + b).getValue(); // valid
}

Private CRTP-Basisklasse

Manchmal ist es erforderlich, dass eine Richtlinie Zugriff auf die abgeleitete Klasse benötigt:

// possible policy used for flexible-class.
template<typename Derived>
struct Policy {
    void doSomething() {
        // casting this to Derived* requires us to see that we are a 
        // base-class of Derived.
        some_type const& t = static_cast<Derived*>(this)->getSomething();
    }
};

// note, derived privately
template<template<typename> class SomePolicy>
struct FlexibleClass : private SomePolicy<FlexibleClass> {
    // we derive privately, so the base-class wouldn't notice that, 
    // (even though it's the base itself!), so we need a friend declaration
    // to make the base a friend of us.
    friend class SomePolicy<FlexibleClass>;

    void doStuff() {
         // calls doSomething of the policy
         this->doSomething();
    }

    // will return useful information
    some_type getSomething();
};

Ein ungekünsteltes Beispiel dafür finden Sie in diese Antwort. Ein anderer Code, der das verwendet, ist in diese Antwort. Die CRTP-Basis überträgt diesen Zeiger, um auf Datenfelder der abgeleiteten Klasse mit Hilfe von Data-Member-Zeigern zugreifen zu können.

47voto

Konrad Rudolph Punkte 503837

@roo : Die Kapselung wird hier nicht gebrochen, da die Klasse selbst festlegt, wer auf ihre privaten Mitglieder zugreifen kann. Die Kapselung wäre nur dann gebrochen, wenn dies von außerhalb der Klasse verursacht werden könnte, z.B. wenn Ihre operator << würde verkünden: "Ich bin ein Freund der Klasse foo ."

friend ersetzt die Verwendung von public , nicht die Verwendung von private !

In der C++-FAQ heißt es beantwortet dies bereits .

34voto

Mark Harrison Punkte 281807

Das klassische Beispiel ist die Überladung des Operators<<. Eine weitere häufige Anwendung ist es, einer Hilfs- oder Verwaltungsklasse Zugriff auf Ihre Interna zu gewähren.

Hier sind ein paar Leitlinien, die ich von C++-Freunden gehört habe. Der letzte ist besonders einprägsam.

  • Ihre Freunde sind nicht die Freunde Ihres Kindes.
  • Die Freunde deines Kindes sind nicht deine Freunde.
  • Nur Freunde dürfen deinen Intimbereich anfassen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X