c++ インスタンス - フレンドクラスオブジェクトは、派生クラスオブジェクトの基本クラスのプライベートメンバにアクセスできますか?




初期化 定義 (5)

以下のコードがコンパイルされたことに驚きました。

派生クラスのインスタンスが提供されると、(公に継承された)基本クラスに親しいクラスが基本クラスのメンバーにアクセスできるように見えます。

継承がprivate変更されると、コンパイルは失敗します。

つまり、 F::func(D& d)内でd.b_varはどのように有効ですか。

#include <iostream>
#include <string>
using namespace std;

class B{
    int b_var;
    friend class F;
};

class D: public B{
    int d_var;
};

class F{
    public:
        void func(D &d){
            d.b_var = 5; 
        }
};

int main()
{
    cout<<"fine";
}

Answers

良い答えがすでにありますが、私はいくつかの画像がここでも少し役立つだろうと思います。

これはあなたのBクラスの抽象概念です。 Fはそのすべてのメンバーにアクセスできます。

Dオブジェクトをインスタンス化すると、このようになります。

それはまだBオブジェクトですがDオブジェクトでもあります。 それはいわばB拡張したものです。 FはまだBからある部分にアクセスできますが、 Dからはアクセスできないからです。

これらの抽象化は実際にはメモリ内のレイアウトを表示したり、上書きしたりすることなどを説明していないことに注意してください。しかし、これらはあくまでこの質問のためです。


  1. どういうわけか、友情は継承され、友だちクラスは派生クラスのメンバーにアクセスできるようです。
    つまり、 F::func(D& d)内でd.b_varはどのように有効ですか。

d.b_varは誤解を招く可能性があります。 より正確に言うと(別の見方では)、 b_varは派生クラスD (直接の)メンバーではありません。 代わりに、 Dのオブジェクトには、メンバーb_varを持つ基本クラスBサブオブジェクトが含まれており、フレンドFによってアクセスされる可能性があります。 ( d.b_vardB::b_var書くこともできdB::b_var 。)

派生クラス[class.derived]

基本指定子リストは、派生クラスtypeのオブジェクトに含まれる基本クラスサブオブジェクトの型を指定します。 [例:

struct Base {
  int a, b, c;
};

struct Derived : Base {
  int b;
};

struct Derived2 : Derived {
  int c;
};

ここでは、クラスDerived2のオブジェクトは、クラスDerivedのサブオブジェクトを持ち、そのサブオブジェクトはクラスBaseサブオブジェクトを持ちます。 - 終了例]

そして

  1. 継承がprivate変更されると、コンパイルは失敗します。

なぜなら

class B {
    int b_var;
    friend class F;
};

class D: private B {
    int d_var;
};

class F{
public:
    void func(D &d) {
        d.b_var = 5;  // Fail. Can't access subobject of B
        d.d_var = 5;  // Fail. Can't access member of D
    }
};

それから

class B {
    int b_var;
};

class D: private B {
    friend class F;
    int d_var;
};

class F{
public:
    void func(D &d) {
        d.b_var = 5;  // Fail. Can't access b_var of subobject of B
        d.d_var = 5;  // Fine.
    }
};

最後のケースでは、たとえFDクラスの友人であっても、 Dすべての非公開メンバーまたは保護メンバーにアクセスできますが、サブオブジェクトBメンバーは含まれません。


class Dオブジェクトは、2つの部分から構成されています。

part containing members of B 
part containing members of D

そのため、オブジェクトスライスの概念は、次のように機能します。

D objD;
B objB = objD;

これでobject of class D内部object of class D objBを介してpart containing members of Bからアクセスできます。 コンパイラは、 class D内の2つの部分を覚えているか区別できます。 だからコンパイラはwhatを通して何がアクセスされているのか知っている。

ステートメントfriend class F; class B内部でmember functions of class F class Bprivate, protected and publicメンバprivate, protected and publicメンバ、 private, protected and publicメンバにアクセスできることmember functions of class F単に通知します。 つまりmember functions of class Fclass Bすべてのメンバーはpublicです。

実際、すべてのクラスの内部には、アクセシビリティに関する3つのセクションがあります。

public
protected
private 

だから我々はいくつかのclass Bを宣言すると:

class B
{
    public:
        int a;
    protected:
        int b;
    public:
        int c;
};

その後、次の3つのセクションが上記のようにクラスB内に作成されます。

class Fclass B friendになるように宣言しましょう。

class B
{
    friend class F;
    private:
        int a;
    protected:
        int b;
    public:
        int c;            
};

その後、コンパイラは次のようにセクションを作成します。

class B
{
    friend class F;
    private:
        int a;
    protected:
        int b;
    public:
        int c;
        //int a;  only for member functions of class F
        //int b;  only for member functions of class F             
};

int a;注意してくださいint a; int b; class F member functionsとして公開されています。

class Dclass Bからpublic派生した場合、 class B publicセクションはclass D publicセクションになります。 同様に、 class B protectedセクションはclass D protectedセクションになります。 したがって、 class B publicセクション部分は、 class Dオブジェクトを介してアクセスできます。 そしてB::a; そしてB::b;members functions of class Fパブリックセクションにあるため、 B::bおよびB::bclass Dオブジェクトを介してアクセスできます。 また、派生int a;後に注意してくださいint a; int b; class Dメンバーになっても、コンパイラはそれらを区別してpart of class Bと見なすことができます。

class Dclass Bからprivately派生した場合、 class Bpublicセクションはclass D privateセクションになります。 同様に、 class B保護されたセクションはclass D保護されたセクションになります。 したがって、 class B内部のpublicセクション部分は、 class Dオブジェクトを介してアクセスすることはできませんclass Bことを思い出してくださいB::a; そしてB::b; もともとmembers functions of class Fパブリックセクションにありmembers functions of class Fが、 private派生の後、 class Bのメンバ、すなわちB::aB::bclass Dプライベートセクションになりました。 したがって、 B::aB::bclass Dオブジェクトを介してアクセスすることはできません 。 また、派生int a;後に注意してくださいint a; int b; class Dメンバーになっても、コンパイラはそれらを区別してpart of class Bと見なすことができます。 派生の後、 class B何人かのメンバーのアクセシビリティとルールは変わりました。

この質問はpublic, protected and private派生の効果に関係しているので、完全を期すためにどうぞ


パブリック継承が使用されている場合、 DBです。 だからb_varアクセスするb_varはまだ完全に合法です。
ただし、 d_varにアクセスしようとすると、友情自体は継承されないため、エラーが発生します。

継承により、常にベースのすべてのメンバーが派生メンバーになります。 アクセス指定子は、識別子が見える場所にのみ影響します。 そのため、プライベートメンバーに不正にアクセスすると、存在しない識別子にアクセスするのとは異なるエラーが発生します。


Python 3.x:
class MyClass(object): =新しいスタイルのクラス
class MyClass: =新しいスタイルのクラス(暗黙的にオブジェクトから継承)

Python 2.x:
class MyClass(object): =新しいスタイルのクラス
class MyClass: = class MyClass: スタイルクラス

説明:

Python 3.xで基本クラスを定義するとき、定義からオブジェクトを削除することができます。 しかし、これは真剣に問題を追跡するためのドアを開くことができます...

PythonはPython 2.2で新しいスタイルのクラスを導入しました。今は古いスタイルのクラスはかなり古くなっています。 古いスタイルのクラスについての議論は、2.xドキュメントに埋め込まれ、3.xドキュメントには存在しません。

問題は、 Python 2.xの古いスタイルのクラスの構文が、Python 3.xの新しいスタイルのクラスの代替構文と同じことです。 Python 2.xは依然として非常に広く使用されています(GAE、Web2Pyなど)。3.xスタイルのクラス定義を無意識に2.xコードに変換するコード(またはコーダー)は、古くなった基本オブジェクトで終わります。 そして、古いスタイルのクラスは誰のレーダーにもないので、何が彼らに当たったのかは分かりません。

ちょうどそれを長い道のりで綴り、2.xの開発者には涙を節約してください。





c++ inheritance private friend