14

少し混乱しているコンパイルエラーが発生します。これはVS2003にあります。

エラー C2248: 'A::y': クラス 'A' で宣言された保護されたメンバーにアクセスできません

class A
{
public:
  A() : x(0), y(0) {}
protected:
  int x;
  int y;
};

class B : public A
{
public:
  B() : A(), z(0) {}
  B(const A& item) : A(), z(1) { x = item.y;}
private:
  int z;
};

問題は x = item.y; にあります。

アクセスは保護されていると指定されています。クラス B のコンストラクターが A::y にアクセスできないのはなぜですか?

4

3 に答える 3

5

これは次の理由によるものです。

class base_class
{
protected:
    virtual void foo() { std::cout << "base::foo()" << std::endl; }
};

class A : public base_class
{
protected:
    virtual void foo() { std::cout << "A::foo()" << std::endl; }
};

class B : public base_class
{
protected:
    virtual void foo() { std::cout << "B::foo()" << std::endl; }

public:
    void bar(base_class *b) { b->foo(); }
};

それが合法である場合、これを行うことができます:

A a;
B b;
b.bar(&a);

protectedまた、B から A のメンバーを呼び出すことになりますが、これは許可されていません。

于 2010-04-01T03:22:09.203 に答える
3

他の回答は、 「is-a」であっても、Bオブジェクトが例の保護された部分にアクセスできないようにする理由を説明しています。もちろん、この問題を解決する最も簡単な方法は、パブリックの一部を作成するか、パブリックにアクセス可能なアクセサメソッドを使用することです。ABAA you want access to

ただし、それが不適切であると判断する場合があります(または、の定義を制御できない場合がありますA)。Aここでは、問題を回避するためのいくつかの提案を、破壊のアクセス制御の昇順で示します。これらの回避策はすべて、class Aがコピー構築可能であることを前提としていることに注意してください。

最初のケースでは、コピーコンストラクターを使用しAてオブジェクトのその部分の初期状態を設定し、B後で修正します。

class B1 : public A
{
public:
  B1() : A(), z(0) {}
  B1(const A& item) : A(item), z(1) {
    // fix up the A sub-object that was copy constructed 
    //  not quite the way we wanted
    x = y;
    y = 0;
  }
private:
  int z;
};

私はそれを信じられないほど混乱させ、おそらく非常にエラーが発生しやすいと思います(Aオブジェクト内のサブオブジェクトBをコンストラクターに渡されるオブジェクトとは異なるものにしたいA場合-異常な状況ですが、それが問題で与えられたものです)。ただし、それを実行できるという事実は、以下のより破壊的な例を正当化するものです...

次の例では、アクセスしたいオブジェクトBの正確な複製を持つ一時オブジェクトを作成します。次に、一時オブジェクトをA使用して、保護されたアイテムにアクセスできます。B

class B2 : public A
{
public:
  B2() : A(), z(0) {}
  B2(const A& item) : A(), z(1) {
    // create a special-use B2  object that can get to the 
    //  parts of the A object we want access to
    B2 tmp( item, internal_use_only);

    x = tmp.y;  // OK since tmp is of type B
  }

private:
  int z;

  // create a type that only B2 can use as a 
  //    'marker' to call a special constructor 
  //    whose only purpose in life is to create
  //    a B object with an exact copy of another
  //    A sub-object in it
  enum internal_use {
    internal_use_only
  };
  B2( const A& item, internal_use marker) : A(item), z(0) {};
};

その解決策は最初の解決策よりも少し混乱が少ないと思いますが、それでも(私の意見では)混乱しています。私たちが望むAオブジェクトの部分にたどり着くためだけにBオブジェクトのろくでなしバージョンを持っているのは奇妙です。

A必要なアクセスを提供するオブジェクト用の特別なプロキシを作成することで、それについて何かを行うことができます。Aこれは「最も破壊的な」回避策であることに注意してください。これは、自分自身のサブクラスでなくても、の保護された部分に到達するためにどのクラスでも実行できるためAです。クラスの場合、オブジェクトBの保護された部分に到達することにはある程度の正当性があります。これは-aであり、すでに見てきたように、すでに持っている権限のみを使用してアクセスできるようにする回避策があるため、これは、の場合のこれらの回避策のよりクリーンなバージョンです。ABAclass Bclass B

class B3 : public A
{
public:
  B3() : A(), z(0) {}
  B3(const A& item) : A(), z(1) { 
    // a special proxy for A objects that lets us
    //  get to the parts of A we're interested in
    A_proxy tmp( item);
    x = tmp.get_y();
  }

private:
  int z;

    class A_proxy : public A
    {
    public:
        A_proxy( const A& other) : A(other) {};
        int get_x() {return x;};
        int get_y() {return y;};
    };

};
于 2010-04-01T15:37:42.803 に答える
1

IBM のドキュメントは、それを最もよく要約しています。

保護された非静的基本クラス メンバーには、次のいずれかを使用して、その基本クラスから派生した任意のクラスのメンバーおよびフレンドがアクセスできます。

  • 直接的または間接的に派生したクラスへのポインター
  • 直接的または間接的に派生したクラスへの参照
  • 直接的または間接的に派生したクラスのオブジェクト

したがって、上記の例を基礎として使用します。

B::B(const A& item) : A(), z(1) {
  // NOT OK because `item` is not a reference to the derived class B
  //int i = item.y; 

  // OK because `item` reinterpreted as a reference to the derived class B
  // Do not do this (bad!) -- for illustrative purposes only
  int i = reinterpret_cast< const B& >(item).y;

  // OK because it is equivalent to `this->x = i`,
  //  where `this` is a pointer to the derived class B
  x = i;
}
于 2010-04-01T04:31:21.140 に答える