web-dev-qa-db-ja.com

保護されたフィールドでの微妙な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
43
wcochran

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

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

標準(2003)の関連テキストは次のとおりです

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

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

そして、この例は標準(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()は_D2_のフレンド関数であり、mem()は_D2_のメンバー関数であり、g()は友達も会員も機能しません。

25
Nawaz

検討してください:

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.
  }
};
14
Billy ONeal

公開継承
基本クラスのすべての_Public members_は、派生クラスの_Public Members_になります
基本クラスのすべての_Protected members_は、_Protected Members_の_Derived Class_になります。

上記のルールに従って:
xの保護されたメンバーAがクラスBの保護されたメンバーになります。

_class B_は、メンバー関数fooで独自の保護されたメンバーにアクセスできますが、すべてのAクラスから派生したわけではないAのメンバーにのみアクセスできます。

この場合、_class B_にはAポインターaが含まれています。この含まれているクラスの保護されたメンバーにアクセスできません。

_B::foo()に含まれる_class B_ポインタb

ルールは:
C++では、アクセス制御はオブジェクトごとではなく、クラスごとに機能します。
したがって、_class B_のインスタンスは、_class 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;
}
_
3
Alok Save

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

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

_b->x_は(継承により)クラスBのインスタンスの保護されたメンバーを指すため、B::foo()はそれにアクセスできます。

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

1
firyice

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

一方、クラスBderivesはクラスAからパブリックに公開されるため、クラスBには、クラスxのすべてのメンバーがアクセスできる(保護された)メンバーBがあります。

0
Kerrek SB

基本的な概念から始めましょう

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 B : public A {
protected:
  A *a;
public:
  void foo() {
    int u = x;     // OK : accessing inherited protected field x
    int w = a->x;  // ERROR : accessing a's protected field x
  }
};

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

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は純粋なオブジェクト指向です:)

0
mac