保護されたフィールドでの微妙な C++ 継承エラー 質問する

保護されたフィールドでの微妙な C++ 継承エラー 質問する

以下は、インスタンスの保護されたフィールド x にアクセスする微妙な例です。B は A のサブクラスなので、B 型の変数はすべて A 型でもあります。B::foo() は b の x フィールドにアクセスできて、a の x フィールドにアクセスできないのはなぜでしょうか。

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++で発生するエラーは次のとおりです。

$ 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

ベストアンサー1

Bは からパブリックに継承されるためA、 A の保護されたメンバーは B の保護されたメンバーになり、 B はメンバー関数から通常どおり保護されたメンバーにアクセスできます。 つまり、 のオブジェクトは、そのメンバー関数からBの保護されたメンバーにアクセスできます。B

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

以下は標準規格(2003)の関連テキストです。

11.5 保護されたメンバーアクセス [class.protected]

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

この例は、標準規格 (2003) 自体から次のように導かれます。

[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]

上記の例では、fr()は のフレンド関数D2mem()は のメンバー関数D2、 はg()フレンドでもメンバー関数でもないことに注意してください。

おすすめ記事