377

私はC++ FAQを読んでいて、friend宣言に興味がありました。個人的には使ったことはありませんが、言語を探求することに興味があります。

を使用する良い例は何friendですか?


FAQ をもう少し読んでみると、<< >>オペレーターがオーバーロードし、それらのクラスのフレンドとして追加するというアイデアが気に入っています。ただし、これがカプセル化を壊さない方法はわかりません。これらの例外が OOP の厳格さの範囲内にとどまることができるのはいつですか?

4

30 に答える 30

354

friendまず(IMO)役に立たないと言う人の言うことを聞かないでください。それは便利です。多くの場合、一般公開を意図していないデータや機能を持つオブジェクトが存在します。これは、さまざまな領域に表面的にしか精通していない多くの作成者がいる大規模なコードベースに特に当てはまります。

フレンド指定子の代替手段はありますが、多くの場合、扱いにくい (cpp レベルの具体的なクラス/マスクされた型定義) か、絶対確実ではありません (コメントまたは関数名の規則)。

答えに。

指定子により、指定されたfriendクラスは、フレンド ステートメントを作成するクラス内の保護されたデータまたは機能にアクセスできます。たとえば、以下のコードでは、誰でも子供に名前を尋ねることができますが、名前を変更できるのは母親と子供だけです。

Window などのより複雑なクラスを検討することで、この単純な例をさらに進めることができます。ほとんどの場合、Window には、公開してはならない多くの関数/データ要素がありますが、WindowManager などの関連クラスによって必要とされます。

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 );
};
于 2008-08-20T05:48:22.717 に答える
170

職場では、コードのテストに友人を幅広く使用しています。これは、メインアプリケーションコードに適切なカプセル化と情報隠蔽を提供できることを意味します。ただし、友人を使用して内部状態とテスト用のデータを検査する個別のテストコードを作成することもできます。

私はあなたのデザインの本質的な構成要素としてfriendキーワードを使用しないと言っておけば十分です。

于 2008-08-30T09:59:53.063 に答える
100

このfriendキーワードには、いくつかの適切な用途があります。私がすぐに目にする2つの用途は次のとおりです。

友達の定義

フレンド定義では、クラス スコープで関数を定義できますが、関数はメンバー関数として定義されず、囲んでいる名前空間の自由な関数として定義され、引数依存のルックアップを除いて通常は表示されません。これにより、演算子のオーバーロードに特に役立ちます。

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
}

プライベート CRTP 基本クラス

ポリシーが派生クラスにアクセスする必要がある場合があります。

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

この回答には、その不自然な例があります。それを使用する別のコードは、この回答にあります。CRTP ベースは、データ メンバー ポインターを使用して派生クラスのデータ フィールドにアクセスできるように、そのポインターをキャストします。

于 2008-12-13T15:49:08.777 に答える
45

@roo:クラス自体がプライベートメンバーにアクセスできるユーザーを決定するため、ここではカプセル化が壊れていません。カプセル化が破られるのは、これがクラスの外部から発生した場合、たとえばoperator <<「私はクラスの友達です」と宣言した場合のみですfoo。</ p>

friendpublicの使用ではなく、の使用を置き換えます。private

実際、C++FAQはすでにこれに答えています。

于 2008-08-20T07:16:26.810 に答える
29

標準的な例は、operator<< をオーバーロードすることです。もう 1 つの一般的な用途は、ヘルパーまたは管理者クラスに内部へのアクセスを許可することです。

C++ の仲間について聞いたガイドラインをいくつか紹介します。特に印象に残っているのはラストです。

  • あなたの友達はあなたの子供の友達ではありません。
  • 子供の友達はあなたの友達ではありません。
  • あなたのプライベートな部分に触れることができるのは友達だけです。
于 2008-08-20T07:05:04.030 に答える
22

編集: よくある質問をもう少し読んで、<< >> 演算子をオーバーロードし、これらのクラスのフレンドとして追加するというアイデアが好きですが、これがカプセル化を壊さない方法がわかりません

カプセル化をどのように破りますか?

データ メンバーへの無制限のアクセスを許可すると、カプセル化が解除されます。次のクラスを検討してください。

class c1 {
public:
  int x;
};

class c2 {
public:
  int foo();
private:
  int x;
};

class c3 {
  friend int foo();
private:
  int x;
};

c1明らかにカプセル化されていません。誰でもそれを読んで変更することができますx。あらゆる種類のアクセス制御を強制する方法はありません。

c2明らかにカプセル化されています。への公開アクセスはありませんx。できることは、クラスに対して意味のある操作fooを実行する関数を呼び出すことだけです。

c3? それはあまりカプセル化されていませんか?への無制限のアクセスを許可しxますか? 未知の機能へのアクセスを許可しますか?

いいえ。クラスのプライベート メンバーにアクセスできる関数は1 つだけです。やったようc2に。と同じようc2に、アクセスできる関数は「ランダムな未知の関数」ではなく、「クラス定義にリストされている関数」です。と同じようc2に、クラス定義を見るだけで、誰がアクセスできるかの完全なリストを確認できます。

では、これはどのようにカプセル化されていないのでしょうか? 同じ量のコードで、クラスのプライベート メンバーにアクセスできます。そして、アクセス権を持つ全員がクラス定義にリストされています。

friendカプセル化を壊しません。「OOP」と言うとき、実際には「Java」を意味するため、一部の Java プログラマーは不快に感じます。彼らが「カプセル化」と言うとき、それは「private メンバーを任意のアクセスから保護する必要がある」という意味ではなく、「private メンバーにアクセスできる唯一の関数がクラス メンバーである Java クラス」という意味です。いくつかの理由

まず、すでに示したように、制限が多すぎます。フレンド メソッドが同じことを許可されるべきではない理由はありません。

第二に、制限が不十分です。4 番目のクラスを考えてみましょう。

class c4 {
public:
  int getx();
  void setx(int x);
private:
  int x;
};

前述の Java の考え方によれば、これは完全にカプセル化されています。 それでも、絶対に誰でも x の読み取りと変更を許可します。それはどのように理にかなっていますか?(ヒント:ありません)

結論: カプセル化とは、どの関数がプライベート メンバーにアクセスできるかを制御できるようにすることです。これらの関数の定義が正確にどこにあるかということではありません。

于 2009-09-07T09:24:47.820 に答える
10

Andrew の例のもう 1 つの一般的なバージョン、恐ろしいコード対句

parent.addChild(child);
child.setParent(parent);

両方の行が常に一緒に実行され、一貫した順序で行われるかどうかを心配する代わりに、メソッドをプライベートにして、一貫性を強制するフレンド関数を使用できます。

class Parent;

class Object {
private:
    void setParent(Parent&);

    friend void addChild(Parent& parent, Object& child);
};

class Parent : public Object {
private:
     void addChild(Object& child);

     friend void addChild(Parent& parent, Object& child);
};

void addChild(Parent& parent, Object& child) {
    if( &parent == &child ){ 
        wetPants(); 
    }
    parent.addChild(child);
    child.setParent(parent);
}

つまり、パブリック インターフェイスを小さく保ち、フレンド関数内のクラスとオブジェクトを横断する不変条件を適用できます。

于 2008-09-10T02:52:54.243 に答える
8

フレンド アクセスを使用する便利な場所を見つけました: プライベート関数の単体テスト。

于 2015-02-19T19:34:00.153 に答える
8

Private/Protected/Public 権限を使用して、メンバーと関数のアクセス権を制御しますか? したがって、これら 3 つのレベルのそれぞれのアイデアが明確であると仮定すると、何かが欠けていることが明らかになるはずです...

たとえば、保護されたメンバー/関数の宣言はかなり一般的です。あなたは、この機能がにとっても手の届かないところにあると言っています(もちろん、継承された子を除く)。しかし、例外はどうですか?どのセキュリティ システムでも、ある種の「ホワイト リスト」を持つことができますよね?

そのため、友人を使用すると、堅実なオブジェクトの分離を柔軟に行うことができますが、正当化されていると感じるものに対して「抜け穴」を作成することができます。

なくてもいいデザインは必ずあるので、必要ないと言う人もいると思います。グローバル変数の議論に似ていると思います: You should never use them. There are always a way to do without them... しかし実際には、それが (ほとんど) 最もエレガントな方法になる場合があります。 .. これは友達も同じだと思います。

設定関数を使用せずにメンバー変数にアクセスできること以外は、実際には何の役にも立たない

それは正確にはそれを見る方法ではありません。アイデアは、誰が何にアクセスできるかを制御することであり、設定機能の有無はほとんど関係ありません。

于 2008-08-20T06:10:58.263 に答える
5

C++ の作成者は、それはカプセル化の原則を破るものではないと言っています。彼の言葉を引用します。

「友達」はカプセル化に違反していますか? いいえ、違います。「フレンド」は、メンバーシップと同様に、アクセスを許可するための明示的なメカニズムです。(標準準拠プログラムでは) ソースを変更せずにクラスへのアクセスを自分自身に許可することはできません。

クリア以上です...

于 2010-02-11T14:42:53.783 に答える
5

Friend は、コンテナを構築していて、そのクラスのイテレータを実装したい場合に便利です。

于 2008-08-25T12:11:39.620 に答える
4

簡単な答えは次のとおりです。実際にカプセル化が改善される場合は、 friendを使用してください。読みやすさと使いやすさの向上(演算子<<と>>は標準的な例です)も正当な理由です。

カプセル化を改善する例としては、他のクラスの内部と連携するように特別に設計されたクラス(テストクラスが思い浮かびます)が良い候補です。

于 2009-01-16T08:33:42.247 に答える
4

私が以前働いていた会社で、友人を使ってまともな影響を与えたという興味深い問題が発生しました。私はフレームワーク部門で働き、カスタムOS上に基本的なエンジンレベルのシステムを作成しました。内部的にはクラス構造がありました:

         Game
        /    \
 TwoPlayer  SinglePlayer

これらのクラスはすべてフレームワークの一部であり、私たちのチームによって維持されていました。同社が制作したゲームは、Gamesの子供たちの1人から派生したこのフレームワークの上に構築されました。問題は、ゲームにはSinglePlayerとTwoPlayerがアクセスする必要のあるさまざまなものへのインターフェイスがありましたが、フレームワーククラスの外部に公開したくないということでした。解決策は、これらのインターフェースをプライベートにし、TwoPlayerとSinglePlayerが友情を介してそれらにアクセスできるようにすることでした。

正直なところ、この問題全体は、システムをより適切に実装することで解決できたはずですが、私たちは自分たちが持っていたものに縛られていました。

于 2008-09-04T23:43:46.817 に答える
3

TDD を何度も実行するために、C++ で「friend」キーワードを使用しました。

友人は私のすべてを知ることができますか?


更新: Bjarne Stroustrup サイトから、「友人」キーワードに関するこの貴重な回答を見つけました。

「フレンド」は、メンバーシップと同様に、アクセスを許可するための明示的なメカニズムです。

于 2008-08-20T08:32:26.583 に答える
3

別の用途:フレンド(+ 仮想継承) を使用して、クラスからの派生を回避できます (別名: 「クラスを分割不可能にする」) => 1 , 2

2から:

 class Fred;

 class FredBase {
 private:
   friend class Fred;
   FredBase() { }
 };

 class Fred : private virtual FredBase {
 public:
   ...
 }; 
于 2009-09-07T09:38:07.617 に答える
3

キーワードをいつ/どこで使用するかについては非常に注意する必要があります。あなたのfriendように、私はめったに使用していません. 以下は、使用上の注意friendと代替手段です。

2 つのオブジェクトを比較して、それらが等しいかどうかを確認したいとします。次のいずれかを実行できます。

  • アクセサー メソッドを使用して比較を行います (すべての ivar をチェックし、等しいかどうかを判断します)。
  • または、すべてのメンバーを公開することで、すべてのメンバーに直接アクセスできます。

最初のオプションの問題は、それが多くのアクセサーになる可能性があることです。これは、直接変数アクセスよりも (わずかに) 遅く、読みにくく、扱いにくいです。2 番目のアプローチの問題は、カプセル化を完全に破ることです。

クラスのプライベートメンバーへのアクセスを取得できる外部関数を定義できればいいのですが。friendこれは、次のキーワードで実行できます。

class Beer {
public:
    friend bool equal(Beer a, Beer b);
private:
    // ...
};

このメソッドは、とのプライベート メンバー ( 、 などの可能性があります)に直接equal(Beer, Beer)アクセスできるようになりました。abchar *brandfloat percentAlcoholfriend== operator

注意すべき点がいくつかあります。

  • Afriendはクラスのメンバ関数ではありません
  • クラスのプライベートメンバーへの特別なアクセスを持つ通常の関数です
  • すべてのアクセサーとミューテーターをフレンドに置き換えないでください (すべてを作成することもできますpublic!)
  • 友情は互角ではない
  • 友情は推移的ではない
  • 友情は遺伝しない
  • または、C++ の FAQ で説明されているように、 「私があなたにフレンドシップ アクセスを許可したからといって、自動的にあなたの子供に私へのアクセスを許可したり、あなたの友人へのアクセスを自動的に許可したり、私にあなたへのアクセスを自動的に許可したりすることはありません。 ."

friends他の方法で行うのがはるかに難しい場合にのみ、私は実際に使用します。別の例として、、、、、 、 などfriendsの相互運用性のために、多くのベクトル数学関数が作成されることがよくあります。また、どこでもアクセサーを使用するよりも、友達になる方がはるかに簡単です。指摘したように、 (デバッグに非常に便利)やおそらく演算子に適用すると便利なことがよくありますが、次のような用途にも使用できます。Mat2x2Mat3x3Mat4x4Vec2Vec3Vec4friend<<>>==

class Birds {
public:
    friend Birds operator +(Birds, Birds);
private:
    int numberInFlock;
};


Birds operator +(Birds b1, Birds b2) {
    Birds temp;
    temp.numberInFlock = b1.numberInFlock + b2.numberInFlock;
    return temp;
}

私が言うように、私はまったくfriend頻繁に使用するわけではありませんが、時々それはあなたが必要とするものです. お役に立てれば!

于 2012-12-29T02:55:28.417 に答える
2

保護された関数をユニットテストするためにfriend-keywordのみを使用しています。保護された機能をテストするべきではないと言う人もいます。ただし、新しい機能を追加するときに、この非常に便利なツールを見つけました。

ただし、クラス宣言で直接キーワードを使用するのではなく、気の利いたテンプレートハックを使用してこれを実現します。

template<typename T>
class FriendIdentity {
public:
  typedef T me;
};

/**
 * A class to get access to protected stuff in unittests. Don't use
 * directly, use friendMe() instead.
 */
template<class ToFriend, typename ParentClass>
class Friender: public ParentClass
{
public:
  Friender() {}
  virtual ~Friender() {}
private:
// MSVC != GCC
#ifdef _MSC_VER
  friend ToFriend;
#else
  friend class FriendIdentity<ToFriend>::me;
#endif
};

/**
 * Gives access to protected variables/functions in unittests.
 * Usage: <code>friendMe(this, someprotectedobject).someProtectedMethod();</code>
 */
template<typename Tester, typename ParentClass>
Friender<Tester, ParentClass> & 
friendMe(Tester * me, ParentClass & instance)
{
    return (Friender<Tester, ParentClass> &)(instance);
}

これにより、次のことが可能になります。

friendMe(this, someClassInstance).someProtectedFunction();

少なくともGCCとMSVCで動作します。

于 2009-09-07T09:03:21.120 に答える
2

operator<< と operator>> に関しては、これらの演算子を友達にする正当な理由はありません。それらがメンバー関数であってはならないのは事実ですが、友達である必要もありません。

最善の方法は、パブリックの print(ostream&) および read(istream&) 関数を作成することです。次に、これらの関数に関して operator<< と operator>> を記述します。これにより、これらの関数を仮想化できるという追加の利点が得られ、仮想シリアライゼーションが提供されます。

于 2008-08-21T13:03:12.460 に答える
2

C++ では、"friend" キーワードは、オペレーターのオーバーロードとブリッジの作成に役立ちます。

1.) 演算子のオーバーロードのフレンド キーワード: 演算子のオーバーロードの例: 2 つの float 変数"x" (x 座標用) と "y" (y 座標用)
を持つクラス "Point" があるとします。
ここで、"<<"(抽出演算子) をオーバーロードして、呼び出す"cout << pointobj"と x 座標と y 座標が出力されるようにする必要があります (pointobj はクラス Point のオブジェクトです)。これを行うには、次の 2 つのオプションがあります。

   1.「ostream」クラスで「operator <<()」関数をオーバーロードします。
   2.「Point」クラスで「operator<<()」関数をオーバーロードします。
ここで、最初のオプションは適切ではありません。別のクラスに対してこの演算子を再度オーバーロードする必要がある場合は、「ostream」クラスを再度変更する必要があるためです。
そのため、2 番目のオプションが最適です。これで、コンパイラは "operator <<()"関数を呼び出すことができます:

   1.ostream オブジェクト cout.As の使用: cout.operator<<(Pointobj) (フォーム ostream クラス)。
2. オブジェクトなしで呼び出します。As: operator<<(cout, Pointobj) (Point クラスから)。

Point クラスにオーバーロードを実装したためです。したがって、オブジェクトなしでこの関数を呼び出すには、"friend"キーワードを追加する必要があります。オブジェクトなしでフレンド関数を呼び出すことができるからです。関数宣言は As:
"friend ostream &operator<<(ostream &cout, Point &pointobj);"

2.) ブリッジを作成する際のフレンド キーワード:
2 つ以上のクラスのプライベート メンバー (一般に "ブリッジ" と呼ばれる) にアクセスする必要がある関数を作成する必要があるとします。これを行う方法:
クラスのプライベート メンバーにアクセスするには、そのクラスのメンバーである必要があります。他のクラスのプライベート メンバーにアクセスするには、すべてのクラスでその関数をフレンド関数として宣言する必要があります。例: 2 つのクラス A と B があるとします。関数"funcBridge()"は両方のクラスのプライベート メンバーにアクセスしたいと考えています。次に、両方のクラスが次のように宣言する必要があり"funcBridge()"ます。
friend return_type funcBridge(A &a_obj, B & b_obj);

これは、フレンドキーワードを理解するのに役立つと思います。

于 2016-03-25T17:53:35.540 に答える
1

TDD を何度も実行するために、C++ で「friend」キーワードを使用しました。
友人は私のすべてを知ることができますか?

いいえ、それは一方通行の友情です :`(

于 2008-08-20T09:19:44.720 に答える
1

私が使用する特定のインスタンスの 1 つは、 Singletonクラスfriendを作成するときです。このキーワードを使用すると、クラスに常に "GetInstance()" メソッドを使用するよりも簡潔なアクセサー関数を作成できます。friend

/////////////////////////
// Header file
class MySingleton
{
private:
    // Private c-tor for Singleton pattern
    MySingleton() {}

    friend MySingleton& GetMySingleton();
}

// Accessor function - less verbose than having a "GetInstance()"
//   static function on the class
MySingleton& GetMySingleton();


/////////////////////////
// Implementation file
MySingleton& GetMySingleton()
{
    static MySingleton theInstance;
    return theInstance;
}
于 2008-08-20T13:40:41.583 に答える
1

ツリーの例は非常に良い例です。継承関係を持たずに、オブジェクトをいくつかの異なるクラスに実装しています。

コンストラクターを保護し、人々に「友達」の工場を強制的に使用させるためにも必要になるかもしれません。

...わかりました、率直に言って、それがなくても生きられます。

于 2008-08-20T05:51:21.850 に答える
1

フレンド関数とクラスは、クラスのプライベートおよび保護されたメンバーへの直接アクセスを提供し、一般的なケースでカプセル化を壊さないようにします。ほとんどの使用は ostream で行われます: 次のように入力できるようにしたいと考えています:

Point p;
cout << p;

ただし、これには Point のプライベート データへのアクセスが必要になる場合があるため、オーバーロードされた演算子を定義します。

friend ostream& operator<<(ostream& output, const Point& p);

ただし、カプセル化には明らかな影響があります。まず、フレンド クラスまたは関数は、クラスのすべてのメンバーに完全にアクセスできるようになりました。第 2 に、クラスとフレンドの実装は、クラスの内部変更がフレンドを壊す可能性があるところまで絡み合っています。

友達をクラスの延長と見なす場合、論理的に言えば、これは問題ではありません。だが、それならば、そもそもなぜ仲間を突き出す必要があったのだろう。

「友人」が達成しようとしているのと同じことを達成するには、カプセル化を壊すことなく、次のようにします。

class A
{
public:
    void need_your_data(B & myBuddy)
    {
        myBuddy.take_this_name(name_);
    }
private:
    string name_;
};

class B
{
public:
    void print_buddy_name(A & myBuddy)
    {
        myBuddy.need_your_data(*this);
    }
    void take_this_name(const string & name)
    {
        cout << name;
    }
}; 

カプセル化は壊れていません。クラス B は A の内部実装にアクセスできませんが、結果は、B を A のフレンドとして宣言した場合と同じです。コンパイラは関数呼び出しを最適化するため、結果は同じになります。直接アクセスとしての指示。

「友達」を使用することは、議論の余地のある利点を持つ単純なショートカットですが、明確なコストだと思います。

于 2012-03-28T14:08:56.020 に答える
0

最も厳密で純粋なOOPの原則を順守し、どのクラスのデータメンバーにもアクセサーないようにすることができます。そのため、すべてのオブジェクトは、間接メッセージを介してのみデータを操作できる唯一のオブジェクトである必要があります。つまり、メソッド。

ただし、C#にも内部可視性キーワードがあり、Javaにはいくつかの点でデフォルトのパッケージレベルのアクセシビリティがあります。C ++は、他のどのクラスと他のクラスだけがクラスを見ることができるかを正確に指定することにより、クラスの可視性の妥協を最小限に抑えることで、実際にはOOPの理想に近づきます。

私は実際にはC++を使用していませんが、C#に友人がいる場合は、実際によく使用するアセンブリグローバル内部修飾子の代わりにそれを使用します。.NETでの展開の単位はアセンブリであるため、カプセル化を実際に壊すことはありません。

ただし、クロスアセンブリフレンドメカニズムのように機能するInternalsVisibleTo Attribute(otherAssembly)があります。Microsoftは、これをビジュアルデザイナーアセンブリに使用しています。

于 2008-08-20T07:46:14.120 に答える
0

異なるクラス (一方を他方から継承していない) が他方のクラスのプライベートまたは保護されたメンバーを使用している場合、フレンドシップを使用できます。

フレンド関数の典型的なユース ケースは、2 つの異なるクラス間で行われる操作で、両方のプライベートまたはプロテクト メンバーにアクセスする操作です。

http://www.cplusplus.com/doc/tutorial/inheritance/から。

非メンバー メソッドがクラスのプライベート メンバーにアクセスするこの例を見ることができます。このメソッドは、クラスのフレンドとしてこのクラスで宣言する必要があります。

// friend functions
#include <iostream>
using namespace std;

class Rectangle {
    int width, height;
  public:
    Rectangle() {}
    Rectangle (int x, int y) : width(x), height(y) {}
    int area() {return width * height;}
    friend Rectangle duplicate (const Rectangle&);
};

Rectangle duplicate (const Rectangle& param)
{
  Rectangle res;
  res.width = param.width*2;
  res.height = param.height*2;
  return res;
}

int main () {
  Rectangle foo;
  Rectangle bar (2,3);
  foo = duplicate (bar);
  cout << foo.area() << '\n';
  return 0;
}
于 2014-02-06T09:50:38.877 に答える
0

クラスのツリー アルゴリズムを実装するときに、教授から提供されたフレームワーク コードには、ノード クラスのフレンドとしてツリー クラスがありました。

設定関数を使用せずにメンバー変数にアクセスできるようにする以外は、実際には何の役にも立ちません。

于 2008-08-20T05:33:58.337 に答える
-1

友達はコールバックにも役立ちます。静的メソッドとしてコールバックを実装できます

class MyFoo
{
private:
    static void callback(void * data, void * clientData);
    void localCallback();
    ...
};

ここで内部的にcallback呼び出し、インスタンスが含まれています。私の意見では、localCallbackclientData

また...

class MyFoo
{
    friend void callback(void * data, void * callData);
    void localCallback();
}

これにより、フレンドがcppで純粋にcスタイルの関数として定義され、クラスが乱雑にならないようにすることができます。

同様に、私がよく目にするパターンは、クラスの本当にプライベートなメンバーをすべて別のクラスに配置することです。このクラスは、ヘッダーで宣言され、cppで定義され、フレンドリングされます。これにより、コーダーは、クラスの複雑さと内部作業の多くをヘッダーのユーザーから隠すことができます。

ヘッダー内:

class MyFooPrivate;
class MyFoo
{
    friend class MyFooPrivate;
public:
    MyFoo();
    // Public stuff
private:
    MyFooPrivate _private;
    // Other private members as needed
};

cppでは、

class MyFooPrivate
{
public:
   MyFoo *owner;
   // Your complexity here
};

MyFoo::MyFoo()
{
    this->_private->owner = this;
}

ダウンストリームがこのように見る必要のないものを隠すことがより簡単になります。

于 2008-12-12T12:10:05.303 に答える