11

継承を使用して次のように 2 つのクラスがある場合:

class A
{
    ...
}

class B : public A
{
    ...
}

そして、フレンド クラス A として定義された 3 番目のクラス:

class C
{
    friend class A;
}

最初にフレンド クラスを定義したかのように、 from class B( type のオブジェクトでもあるA) のすべてのメンバーにアクセスできますか?class Cclass B

4

8 に答える 8

21

friend船は継承も推移的でもありません。これは、厳密には2つのクラス間の1対1の関係です。

class A {
  friend class B;  
  int Aries;
};

class B {
  friend class C;  
  int Taurus;
};

class C {
  int Leo;
  void Capricorn() {
    A a;
    a.Aries = 0;  // this wont work, C is not a friend of A.
                // friendship is not transitive
  }
};

class D : public C {
  void Gemini() {
    B b;
    b.Taurus = 0;  // this wont work, D is not a friend of B.
                   // friendship is not inherited
  }
};    

class E : public B {
  void Scorpio() {
    C c;
    c.Leo = 0; // this wont work either, friendship is not inherited
  }
};

参照:「C++プログラミング言語」BjarneStroustrup

詳細説明(私のもの):friend船が1対1でなければ、カプセル化は終わりです。クラスは、のクラス宣言がとして宣言されている場合にのみ、のメンバーにBアクセスできることに注意してください。に出荷を強制することはできません。privateAABfriendBfriendA

さて、友情が継承される可能性がある場合、誰かがそれを防ぐことについて何も言わずに、Bのプライベートメンバーにアクセスするために継承する必要があります。また、船を推移的にすることを許可すると、他の問題が発生する可能性があります。これは、が、今度は、まで続く可能性があるためです。、、、...のすべてが、のメンバーにアクセスできるようになりました。これは災害になります。AAfriendBfriend Cfriend DZBCDZAprivate

于 2012-12-12T16:40:14.817 に答える
4

なんらかの理由で、フレンドシップ提供者から派生したクラスの仮想プライベート関数にアクセスできることを誰もが忘れています。

#include <iostream>

class Friend;
class Parent
{
    friend class Friend;
private:
    virtual void nameYourself() { std::cout << "Parent" << std::endl; }
};

class Child : public Parent
{
private:
    virtual void nameYourself() { std::cout << "Child" << std::endl; }
};

class Friend
{
public:
    void foo(Parent *p) { p->nameYourself(); }
};

int main()
{
    Parent p;
    Child c;
    Friend f;
    f.foo(&p);
    f.foo(&c);
    return 0;
}

上記のコードを実行した場合の出力は次のとおりです。

Parent
Child

それが機能する理由はトリッキーで、このポインターがどのように渡されるかに関係しています (vtables を調べてください)。関数宣言から「virtual」キーワードを削除すると、この機能が失われます。

于 2015-07-14T04:16:09.767 に答える
2

標準を引用するには、C ++ 11 11.3 / 10:

友情は継承も推移的でもありません。

派生したクラスの友達も友達の友達も友情の恩恵を受けないことを意味します。

于 2012-12-12T16:50:16.580 に答える
1

上記のMasked Manの回答/コードに追加するもう1つの例は、私が役に立つと思ったものです:

class B {
  friend class F;
  friend class E;
  int Taurus;
};

class E : public B {
  int Egg;
};

class F {
    void Foo () {
       B b;
       b.Taurus = 4;  //Works F is friend of B (of course)
       E e;
       e.Taurus = 6; // Works E is derived from B and F is friend of B 
                  // Taurus is private member of B.
       e.Egg = 5; // Does not work, F is friend of Base Class B but not
               // E, so can't access members of the derived class
    }
};
于 2015-10-14T23:36:13.660 に答える
0

依存していると思います。B の A 部分 (スライスされた部分) からアクセスできます。B 独自の関数を定義した場合は、そうしないと思います。

于 2012-12-12T16:28:06.820 に答える
0
  • いいえ - 継承されません (以下を参照)。B が A のサブクラスであり、C が A のフレンドである場合、B は継承されたメンバーを含む C のプライベート メンバーにアクセスできません。
  • 同様に、A が C のフレンドである場合、または A と C の両方が相互にフレンドである場合、継承されたメンバーを含む C のプライベート メンバーへのアクセスを B に与えることはありません。
  • この URL は、フレンド クラスのサブクラスがフレンド アソシエーションを継承しないことを示しています。

    C++ フレンドの継承?

  • これは、両方の「関連付け (メイン クラス自身のクラスと、メイン クラスと友好的な他のクラスの両方)」に適用されます。問題は、ここでは後者の場合です。

于 2012-12-12T16:46:24.967 に答える
0

何をしようとしているのか理解できませんでしたが、B は A のスーパークラスです。オブジェクトではありません。B と C の間には継承関係はありません

于 2012-12-12T16:37:54.310 に答える
0

Cいいえ、クラス メソッドを直接呼び出すことはできませんが、ポインターでアクセスできます。Aクラスを変更する必要があります:

class C
{
  void method()
  {
  }
  friend class A;
};

class A
{
protected:
  constexpr static void (C::*f)() = &C::method;
};

class B : public A
{
  B()
  {
    //C().method(); ← This wont work
    (C().*f)(); // ← This works fine
  }
};

データメンバーと静的データへのアクセスも簡単です

于 2018-03-15T15:39:55.950 に答える