2011-08-08 13 views
29

以下は、インスタンスの保護されたフィールドxにアクセスする微妙な例です。 BはAのサブクラスなので、B型の変数もA型です。 B :: foo()はbのxフィールドにアクセスできますが、xフィールドにはアクセスできないのはなぜですか?ここで保護されたフィールドの微妙なC++継承エラー

class A { 
protected: 
    int x; 
}; 

class B : public A { 
protected: 
    A *a; 
    B *b; 
public: 
    void foo() { 
    int u = x;  // OK : accessing inherited protected field x 
    int v = b->x; // OK : accessing b's protected field x 
    int w = a->x; // ERROR : accessing a's protected field x 
    } 
}; 

私はグラム公開継承で++

$ g++ -c A.cpp 
A.cpp: In member function ‘void B::foo()’: 
A.cpp:3: error: ‘int A::x’ is protected 
A.cpp:14: error: within this context 

答えて

2

で取得エラーです:
基本クラスの すべてPublic membersはすべて派生クラスのPublic Members &
になりますProtected members eクラスDerived ClassProtected Membersになります。上記の規則1として

Aから
保護部材xクラスBの保護部材となります。

class Bは、そのメンバ関数fooに、独自の保護されたメンバーにアクセスすることができますが、、それができない、それはすべてAのクラスを派生した通過Aのアクセスのみメンバー。この場合

class BAポインタaが含まれ、これは、この含まれるクラスのprotectedメンバにアクセスすることはできません。

なぜB::foo()アクセスのメンバーがclass Bポインタbを含まことができますか?

ルールは次のとおりです。クラス単位ではなく、オブジェクトごとにC++のアクセス制御作品で

したがって、class Bのインスタンスは、class Bという別のインスタンスのすべてのメンバーに常にアクセスできます。ルールを示し

アンサンプルコード:Bため

#include<iostream> 

class MyClass 
{ 
    public: 
     MyClass (const std::string& data) : mData(data) 
     { 
     } 

     const std::string& getData(const MyClass &instance) const 
     { 
      return instance.mData; 
     } 

    private: 
     std::string mData; 
}; 

int main() { 
    MyClass a("Stack"); 
    MyClass b("Overflow"); 

    std::cout << "b via a = " << a.getData(b) << std::endl; 
    return 0; 
} 
+0

である。しかし 'X'は、この例ではB' 'の保護されたメンバーであるような完全なオブジェクト指向プログラミング、あるホープ、アクセスは許可されません。私はこれが質問に答えるとは思わない。 –

+0

@Billy ONeal:C++アクセス制御では、オブジェクト単位ではなく、クラス単位で動作するため、クラスBのオブジェクトはクラスBの別のオブジェクトのメンバにアクセスできます。 –

18

は公にAから継承され、Aの保護部材(単数または複数)Bの保護材(S)となるので、Bは、としての保護部材にアクセスすることができ通常、そのメンバ関数から継承します。つまり、Bのオブジェクトは、そのメンバ関数からBの保護されたメンバにアクセスできます。

ただし、Aの保護されたメンバーには、Aというオブジェクトを使用して、クラスの外部にアクセスすることはできません。

ここ標準から関連するテキスト(2003)

11.5プロテクトメンバアクセス[クラスです。

派生クラスのフレンドまたはメンバー関数が、保護された非静的メンバー関数または基本クラスの保護された非静的データメンバーを参照する場合は、前述の11.102節で説明したものに加えてアクセスチェックが適用されます。 (5.3.1)、へのポインタを作成するには、派生クラス自体(またはそのクラスから派生した任意のクラス)へのポインタ、参照先、またはオブジェクトを経由する必要があります。(5.2.5)。アクセスがメンバへのポインタを形成する場合、ネストされた名前指定子は、派生クラス(またはそのクラスから派生した任意の クラス)の名前を付けます。

、実施例として(2003)標準からそれ自体を次の上記の例fr()

[Example: 

class B { 
    protected: 
    int i; 
    static int j; 
}; 

class D1 : public B { 
}; 

class D2 : public B { 
    friend void fr(B*,D1*,D2*); 
    void mem(B*,D1*); 
}; 

void fr(B* pb, D1* p1, D2* p2) 
{ 
    pb->i = 1; // ill-formed 
    p1->i = 2; // ill-formed 
    p2->i = 3; // OK (access through a D2) 
    p2->B::i = 4; // OK (access through a D2, even though naming class is B) 
    int B::* pmi_B = &B::i; // ill-formed 
    int B::* pmi_B2 = &D2::i; // OK (type of &D2::i is int B::*) 
    B::j = 5; // OK (because refers to static member) 
    D2::j =6; // OK (because refers to static member) 
} 
void D2::mem(B* pb, D1* p1) 
{ 
    pb->i = 1; // ill-formed 
    p1->i = 2; // ill-formed 
    i = 3; // OK (access through this) 
    B::i = 4; // OK (access through this, qualification ignored) 
    int B::* pmi_B = &B::i; // ill-formed 
    int B::* pmi_B2 = &D2::i; // OK 
    j = 5; // OK (because j refers to static member) 
    B::j = 6; // OK (because B::j refers to static member) 
} 
void g(B* pb, D1* p1, D2* p2) 
{ 
    pb->i = 1; // ill-formed 
    p1->i = 2; // ill-formed 
    p2->i = 3; // ill-formed 
} 
—end example] 

D2のフレンド関数である、mem()D2のメンバ関数であり、そしてg()であります友人もメンバーも機能しません。

+1

public継承であるため、保護されたメンバーは 'B'の保護されたメンバーになります。プライベートではありません。 –

+0

@Billy:正しい。答えも訂正しました。 – Nawaz

+0

** Public Ihneritance **において、Baseクラスのprotectedメンバーは、派生クラスの保護されたメンバーとなり、基本クラスのpublicメンバーは派生クラスのpublicメンバーになります。 –

10

は考えてみましょう:

class A { 
protected: 
    int x; 
}; 

class C : public A 
{ 
}; 

class B : public A { 
protected: 
    unique_ptr<A> a; 
public: 
    B() : a(new C) // a now points to an instance of "C" 
    { } 

    void foo() { 
    int w = a->x; // B accessing a protected member of a C? Oops. 
    } 
}; 
+0

それは素晴らしい例です! +1 – jweyrich

+0

'a'と' foo'の両方が 'A'のメンバであれば(つまり' a'は 'C'のインスタンスになるかもしれません)、同じ引数を取るので、それは説明しません。これはC++でうまくコンパイルされます! – wcochran

+0

@wcochran:そうではありません。この例では、 'B'は' C'の継承連鎖には全くありません.Cのいずれの部分にもアクセスすべきではありません。両方が 'A'のメンバーだった場合、' A'は両方のクラスの継承チェーン。 –

0

クラスBはクラスAと同一ではありません。そのため、クラスBのメンバーは、クラスAの非公開メンバーにアクセスできません。

一方、クラスBクラスAから公にを導出するので、クラスB現在、クラスBの任意のメンバーがアクセス可能な(保護された)メンバーxを有しています。

1

なぜB :: foo()はbのxフィールドにアクセスできますが、xフィールドにはアクセスできませんか?

保護されたメンバーには、同じクラス(または派生クラス)の他のメンバーだけがアクセスできます。

b->xは、継承を介してクラスBのインスタンスの保護されたメンバーを指すため、B::foo()にアクセスできます。

a->xは、クラスAのインスタンスの保護されたメンバーを指しているため、B::foo()はアクセスできません。

0

class A { 
protected: 
    int x; 
}; 

class B : public A { 
public: 
    void foo() { 
    int u = x;  // OK : accessing inherited protected field 
    } 
}; 

子が親を継承しているので、子供がXを取得し、基本的な概念で始まります。したがって、子のfoo()メソッドで直接xにアクセスできます。これが保護された変数の概念です。子供の親の保護された変数に直接アクセスすることができます。 注:ここでは、xには直接アクセスできますが、Aのオブジェクトを経由することはできません。違いはなんですか? xは保護されているので、Aの外にあるAの保護されたオブジェクトにアクセスすることはできません。どこにあっても問題ありません。そのため、あなたは次の方法でアクセスすることができません。

ここでは興味深い概念があります。クラス内のオブジェクトを使用して、クラスのプライベート変数にアクセスできます。

class dummy { 
private : 
int x; 
public: 
    void foo() { 
    dummy *d; 
    int y = d->x; // Even though x is private, still you can access x from object of d - But only with in this class. You cannot do the same outside the class. 
    } 
}; 

//同じものが保護された変数です。次の例にアクセスできます。

class B : public A { 
protected: 
    A *a; 
    B *b; 
public: 
    void foo() { 
    int u = x;  // OK : accessing inherited protected field x 
    int y = b->x; // OK : accessing b's protected field x 
    int w = a->x; // ERROR : accessing a's protected field x 
    } 
}; 

はそれが説明:)

C++はJavaは純粋なオブジェクト指向:)

関連する問題