C ++ an einen Freund oder nicht an einen Freund

19

Ich habe ein objektorientiertes Programmieren mit C ++ Kurs in diesem Semester am College und wir lernten über Freundfunktionen.

Ich mag sie instinktiv nicht, weil sie die Sicherheit umgehen können, die Encapsulation und Data Hiding bieten. Ich habe ein paar Artikel im Internet gelesen und einige Leute dachten, es sei eine gute Idee mit legitimen Verwendungszwecken.

Was würde ein OOPs-Experte über Freundesfunktionen in C ++ sagen? Soll ich nur darüber hinweggehen oder mehr darüber erfahren?

nikhil
quelle
@all: Großartige Antworten und Kommentare. Dies ist eine großartige Möglichkeit zu lernen. Ich hätte in keinem Lehrbuch so viel über Freunde erfahren.
Nikhil

Antworten:

13

Es ist nicht immer praktisch, alle Funktionen, die sich auf C ++ - Klassenmitglieder dieser Klasse beziehen, zu erstellen. Stellen Sie sich zum Beispiel eine Implementierung der Vektoralgebra mit Skalarmultiplikation vor. Wir möchten schreiben:

 double a;
 Vector v, w;
 w = v * a;

Wir können dies mit einer Mitgliedsfunktion tun:

public class Vector {
 ...
 Vector operator*(double a);
}

Wir möchten aber auch schreiben:

w = a * v

Dies erfordert eine freie Funktion:

 Vector operator*(double a, Vector v)

Das friendSchlüsselwort wurde zu C ++ hinzugefügt, um diese Verwendung zu unterstützen. Die freie Funktion ist Teil der Implementierung der Vector-Klasse und sollte im selben Header deklariert und in derselben Quelldatei implementiert werden.

In ähnlicher Weise können wir frienddie Implementierung eng gekoppelter Klassen wie einer Sammlung und eines Iterators vereinfachen. Auch hier würde ich beide Klassen im selben Header deklarieren und sie in derselben Quelldatei implementieren.

Kevin Cline
quelle
3
Msgstr "Dies erfordert eine freie Funktion". Nein, tut es nicht: inline Vector operator*(double a, Vector v) { return v*a; }. Canonical Lösung in der Tat.
MSalters
1
@MSalters: Guter Punkt. Ich habe ein schlechtes Beispiel ausgewählt. Ich denke, Ihre Inline-Funktion ist per Definition eine freie Funktion, aber es ist keine Deklaration eines Freundes erforderlich.
Kevin Cline
4
@MSalters: Das gilt nur, wenn * kommutativ zu a und v (x) ist. Wenn die Vektorkomponenten generisch sind (nicht unbedingt Skalare), müssen Sie die Operandenreihenfolge beibehalten
Emilio Garavaglia
Das ist ziemlich theoretisch. Vielleicht wäre der einzige übliche nicht kommutative Fall, inline Vector operator*(double a, Vector v) { return -v*a; }und das erfordert immer noch keine Freundschaft.
MSalters
16

Friend-Funktionen unterscheiden sich hinsichtlich der Kapselung nicht von Member-Funktionen. Sie können jedoch auch andere Vorteile bieten, z. B. generische Vorteile, insbesondere bei Vorlagen. Außerdem können einige Operatoren nur als freie Funktionen angegeben werden. Wenn Sie also möchten, dass sie Mitgliederzugriff haben, müssen Sie dies tunfriend .

Es ist besser für friendeine einzelne Funktion, als gezwungen zu sein, etwas zu machen, das nicht öffentlich sein soll. Das heißt, die ganze Welt kann es benutzen - anstatt nur einer Funktion.

DeadMG
quelle
+1 für Friend-Funktionen unterscheiden sich hinsichtlich der Kapselung nicht von Member-Funktionen. Dies gilt jedoch nur für öffentliche Mitgliederfunktionen.
TheFogger
1
@TheFogger: Vermutlich könntest du auch friendeine Funktion, die auch "privat" ist, zB nur in einer einzigen TU deklarieren.
DeadMG
5

Wenn Sie eine Leidenschaft für das haben, was Sie tun, lernen Sie alles über C ++. Erfahren Sie, wofür sie verwendet werden, wie sie verwendet werden, und entscheiden Sie sich dann - und nur dann -, sie nicht zu verwenden. Zumindest sind Sie darauf vorbereitet, den Code eines anderen Benutzers zu lesen, der diese Facette von C ++ verwendet.

JK
quelle
5

" Was würde ein OOPs-Experte sagen ... " Es hängt hauptsächlich davon ab, wie gut er mit C ++ vertraut ist, dass es sich - seiner eigenen Spezifikation nach - nicht um eine Sprache für Puristen handelt (und dies auch nicht sein möchte).

OOP Zealots verwenden kein C ++ (sie bevorzugen Smalltalk und Java).

Zelots mit funktionaler Programmierung verwenden kein C ++ (sie bevorzugen LISP und seine Nachfolger)

Die meisten OOP-Experten mögen keine Friend-Funktion, nur weil sie möchten, dass sich der OOP-Teil von C ++ wie Smalltalk verhält. Aber C ++ ist kein Smalltalk und sie können nicht einmal verstehen, dass Friend die Kapselung nicht unterbricht , aus dem einfachen Grund, dass eine Funktion nicht mit Ihrer Klasse befreundet sein kann, ohne dass Ihre Klasse dies wünscht .

Und vom Standpunkt der "Funktionalität" gibt es keinen Unterschied zwischen a.fn(b)und fn(a,b)(wo fnist ein Freund): Die beteiligten Parteien sind die gleichen. Eine Syntax ist möglicherweise besser geeignet als eine andere: Wenn fn kommutativ in Bezug auf aund ist b, fn(a,b)ist sie wahrscheinlich besser geeignet a.fn(b)(wenn ein Look eine "besondere Rolle" hat, die es in der Tat nicht hat).

Emilio Garavaglia
quelle
1
"OOP-Fanatiker", die Java mögen, haben OOP nicht verstanden. Getter? Setter? Keine einfache Syntax für Abschlüsse? Um Alan Kay zu paraphrasieren: So hat er sich OOP nicht vorgestellt.
Konrad Rudolph
@Konrad: zealots are ist überlegen unlimitiert gesetzt. Es gibt immer einen Zeloten, der mehr Zeloten hat als ein bestimmter Zelot.
Emilio Garavaglia
Ich muss sagen, ich habe gestimmt, weil mir der letzte Absatz wirklich gut gefallen hat. Das ergibt sehr viel Sinn.
Julealgon
5

Verstößt "Freund" gegen die Kapselung?

Nein, tut es nicht. "Freund" ist genau wie die Mitgliedschaft ein expliziter Mechanismus zum Gewähren des Zugriffs. Sie können sich (in einem standardkonformen Programm) keinen Zugriff auf eine Klasse gewähren, ohne deren Quelle zu ändern.

fredoverflow
quelle
2

Die C ++ - FAQ sind kurz gefasst:

Verwenden Sie ein Mitglied, wenn Sie können, und einen Freund, wenn Sie müssen.

Die FAQ bietet eine der nützlichsten Denkweisen über Freundschaft:

Viele Leute denken, dass ein Freund etwas außerhalb der Klasse ist. Stellen Sie sich stattdessen eine Friend-Funktion als Teil der öffentlichen Schnittstelle der Klasse vor. Eine Friend-Funktion in der Klassendeklaration verletzt die Kapselung nicht mehr als eine öffentliche Member-Funktion die Kapselung: Beide haben genau die gleiche Berechtigung für den Zugriff auf die nicht öffentlichen Teile der Klasse.

Möglicherweise ist die häufigste Verwendung von Friend-Funktionen das Überladen von << für E / A.

Gnawme
quelle
0

Friend-Funktionen werden am besten für benutzerdefinierte Operatordefinitionen verwendet. Sie sind in anderen Situationen hilfreich. Wenn Sie jedoch feststellen, dass Sie häufig Freundesklassen angeben, befinden Sie sich möglicherweise auf einem Umweg über das Design (nur eine gute Selbstprüfung, die Sie beim Schreiben von Code verwenden sollten).

Seien Sie vorsichtig mit der "Sicherheitserklärung" in der ursprünglichen Frage. Zugriffsmodifikatoren verhindern, dass Sie versehentlich fehlerhaften Code schreiben, genau wie der Compiler in gewisser Weise. Zugriffsmodifizierer begrenzen die Schnittstelle und dienen dazu, zu kommunizieren, welche Funktionen für die Verwendung der Klasse wichtig sind (öffentlich und geschützt) und welche Funktionen erstellt wurden, um die Klasse für die Betreuer (privat) hübscher zu gestalten. Modifikatoren stellen keine Sicherheit dar, da es viele Möglichkeiten gibt, an private Daten zu gelangen. Holen Sie sich zum Beispiel einen Zeiger auf die Klasse und ihre Größe und gehen Sie angeln.

anon
quelle
-2

C ++ - Friend-Funktionen stehen in engem Zusammenhang mit der folgenden Funktionalität:

  1. freie funktionen
  2. statische Funktionen
  3. Freund Funktionen

Dies bedeutet, dass sie diesen Zeiger nicht haben und sich somit außerhalb der Klasse / des Objekts befinden. Andererseits nehmen sie oft Parameter, die sie wieder zur Klasse gehören lassen. Hier ist ein Beispiel, das den Zusammenhang verdeutlicht:

class B;
class A {
public:
    friend void f(A &a, B &b);
private:
    int m_a;
};
class B {
public:
   friend void f(A &a, B &b);
private:
   int m_b;
};
void f(A &a, B &b) { /* uses both A's and B's private data */ }

Der einzige Unterschied zwischen statischen Funktionen und Friend-Funktionen besteht darin, dass eine Friend-Funktion mehrere Klassen verwenden kann.

Die Verwendung des Friend-Mechanismus in c ++ erfordert Programmierer, die ungefähr 10-15 Jahre Erfahrung mit der Programmierweise in c ++ haben. Daher sollten Sie dies zunächst vermeiden. Es ist erweiterte Funktion.

tp1
quelle
7
Und Sie haben 10-15 Jahre wie abgeleitet?
DeadMG
10-15 Jahre liegen in der Zeit, in der es tatsächlich notwendig wird.
tp1
3
Sie haben sich also eine Nummer ausgedacht.
DeadMG
3
-1: "Du solltest es vermeiden." Jedes Feature von C ++ wurde erstellt, um ein Problem zu lösen. Wenn dieses Problem auftritt, verwenden Sie die entsprechende Funktion.
Kevin Cline
Danke für den -1. Es gab einen Grund für diesen Kommentar. Schätze, es ist nur ein schwieriges Konzept, dass nicht alle Funktionen für Anfänger geeignet sind.
tp1