友達にC ++


19

私は今学期に大学でc ++コースを使用したオブジェクト指向プログラミングを行っており、友人の機能について学習していました。

カプセル化とデータの隠蔽が提供するセキュリティをバイパスする能力があるため、私は彼らを本能的に嫌い、インターネット上のいくつかの記事を読み、一部の人々はそれがいくつかの合法的な使用で良いアイデアだと思いました。

OOPの専門家は、C ++のフレンド機能について何と言いますか?ざっと目を通すだけですか、それとももっと学ぶ必要がありますか?


@all:素晴らしい答えとコメント、これは学ぶのにとても良い方法です。教科書のそのような詳細で友人について学んだ方法はありません。
-nikhil

回答:


13

そのクラスのC ++クラスメンバに関連するすべての関数を作成することは必ずしも便利ではありません。たとえば、スカラー乗算を使用したベクトル代数の実装を想像してください。書きたい:

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

メンバー関数でこれを行うことができます:

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

しかし、私たちはまた書きたいと思います:

w = a * v

これには無料の機能が必要です。

 Vector operator*(double a, Vector v)

friendキーワードはこの用法をサポートするために、C ++に追加されました。free関数はVectorクラス実装の一部であり、同じヘッダーで宣言され、同じソースファイルで実装される必要があります。

同様にfriend、コレクションやイテレータなどの密結合クラスの実装を簡素化するために使用できます。繰り返しますが、同じヘッダーで両方のクラスを宣言し、同じソースファイルに実装します。


3
「これには無料の機能が必要です」。いいえ、ありません:inline Vector operator*(double a, Vector v) { return v*a; }。実際には標準的なソリューション。
MSalters

1
@MSalters:良い点。私は悪い例を選びました。インライン関数は定義上は無料の関数であると思いますが、フレンド宣言は必要ありません。
ケビンクライン

4
@MSalters:これは、*がaおよびv(x)に関して可換性に関してのみ有効です。ベクトルコンポーネントが汎用である場合(スカラーである必要はありません)、オペランドの順序を維持する必要があります
エミリオガラヴァリア

それはかなり理論的です。おそらく、唯一の一般的な非可換の場合が inline Vector operator*(double a, Vector v) { return -v*a; }あり、それでも友情は必要ありません。
–MSalters

16

フレンド関数は、カプセル化の点でメンバー関数と同じです。ただし、特にテンプレートが関係する場合、より汎用的であるなど、他の利点も提供できます。また、一部の演算子は無料の関数としてのみ指定できるため、メンバーにアクセスを許可する場合は、friendます。

friendあなたが公開したくない何かを強制的に作成するよりも、単一の関数の方が良いです。つまり、1つの関数だけでなく、全世界で使用できるということです。


フレンド関数の +1は、カプセル化の点でメンバー関数と同じです。ただし、これはパブリックメンバー関数にのみ当てはまります。
TheFogger

1
@TheFogger:おそらく、friend単一のTUでのみ宣言されているような、「プライベート」な関数も可能です。
DeadMG

5

あなたがやることに情熱を持っているなら、C ++についてすべてを学んでいるでしょう。それらが何に使われているのか、どのように使用するのかを学び、それから-そしてその時だけ-それらを使わないことに決めます。少なくとも、このC ++のファセットを使用する他の人のコードを読むときには準備ができています。


5

OOPの専門家が言うことは...」それは、主に彼がC ++の専門家であるかどうかに依存します。

OOP ZealotsはC ++を使用しません(Smalltalkを好み、Javaが好きです)。

関数型プログラミングzelotはC ++を使用しません(LISPとその後継を好む)

OOPの専門家のほとんどは、C ++のOOP部分をSmalltalkのように動作させたいという理由だけで、友人機能を嫌います。しかし、C ++はSmalltalkではなく、クラスが必要としない限り関数がクラスのフレンドになれないという非常に単純な理由でフレンドがカプセル化を破らないことすら理解できません

そして、「機能性」との間で、ポイントをスタンドからa.fn(b)してfn(a,b)違いはありません(ここでfn友人がある):関係者は同じです。単純に、ある構文は別の構文よりも適している可能性があります。fnがaand に関して可換であればbfn(a,b)おそらくより適切ですa.fn(b)(実際にはそうではない「特殊な役割」を持つ外観になります)。


1
Javaが好きな「OOP熱狂者」はOOPを理解していません。ゲッター?セッター?クロージャーの簡単な構文はありませんか?アラン・ケイを言い換えると、これは彼がOOPを想像した方法ではありません。
コンラッドルドルフ

@Konrad:熱狂者は、優れた無制限のセットです。常に特定の熱狂者よりも熱狂的な熱狂者がいます。
エミリオガラヴァリア

最後の段落が本当に好きだったので、私は賛成したと言わなければなりません。とても理にかなっています。
-julealgon


2

C ++よくある質問は簡潔です:

可能な場合はメンバーを使用し、必要な場合は友人を使用します。

FAQは、友情についてのより便利な考え方の1つを示しています。

多くの人々は、友人の機能をクラス外の何かと考えています。代わりに、フレンド関数をクラスのパブリックインターフェイスの一部として考えてみてください。クラス宣言のフレンド関数は、パブリックメンバー関数がカプセル化に違反する以上にカプセル化に違反しません。両方とも、クラスの非パブリック部分へのアクセスに関してまったく同じ権限を持っています。

おそらく、フレンド関数の最も一般的な使用法は、I / Oのオーバーロード<<です。


0

フレンド関数は、ユーザー定義のオペレーター定義に最適です。他の状況でも役立ちますが、フレンドクラスを頻繁に指定することに気づいた場合は、デザインの迂回を行っている可能性があります(コードの作成中に使用するのが良い自己チェックです)。

元の質問の「セキュリティ」ステートメントに注意してください。アクセス修飾子は、ある意味でコンパイラと同じように、誤って間違ったコードを書くことを防ぐためにあります。アクセス修飾子はインターフェースを制限し、クラスを使用するために重要な機能(パブリックおよび保護)、およびメンテナーのクラスをきれいにするための一部として作成された機能(プライベート)を伝達します。修飾子は、プライベートデータを取得する多くの方法があるという点でセキュリティを構成しません。たとえば、クラスとそのサイズへのポインターを取得し、釣りに行きます。


-2

C ++フレンド関数は、次の機能と密接に関連しています。

  1. 無料機能
  2. 静的関数
  3. 友達機能

これは、これらがthis-pointerを持たないため、クラス/オブジェクトの外側にあることを意味します。一方、彼らはしばしばそれらを再びクラスに属するようにするパラメータを取ります。リンクを明確にするいくつかの例を次に示します。

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

静的関数とフレンド関数の唯一の違いは、フレンド関数が複数のクラスを使用できることです。

C ++でフレンドメカニズムを使用するには、プログラミングのC ++の方法に10〜15年の経験があるプログラマが必要です。したがって、最初はそれを避ける必要があります。高度な機能です。


7
そして、あなたは10-15年をどのように導きましたか?
DeadMG

10-15年は、実際に最初に必要になったときから来ています。
tp1

3
それで、あなたは勝手に数字を作りました。
DeadMG

3
-1:「回避する必要があります。」C ++のすべての機能は、問題を解決するために作成されました。その問題が発生した場合、適切な機能を使用してください。
ケビンクライン

-1をありがとう。そのコメントには理由がありました。すべての機能が初心者に適しているわけではないというのは、単なる難しい概念だと思います。
tp1
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.