11

私は混乱しています。保護されたデータは、C++の特定のクラスの子によって読み取り/書き込み可能だと思いました。

以下のスニペットはMSコンパイラでコンパイルできません

class A
{
protected:
  int data;
};

class B : public A
{
  public:

  B(A &a)
  {
    data = a.data;
  }
};

int main()
{
  A a;
  B b = a;
  return 0;
}

エラーメッセージ:

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

demoFail.cpp
demoFail.cpp(12) : error C2248: 'A::data' : cannot access protected member declared in class 'A'
        demoFail.cpp(4) : see declaration of 'A::data'
        demoFail.cpp(2) : see declaration of 'A'

私は何が間違っているのですか?

4

4 に答える 4

10

TC ++ PLによると、404ページ:

派生クラスは、それ自体のタイプのオブジェクトに対してのみ基本クラスの保護されたメンバーにアクセスできます。これにより、ある派生クラスが他の派生クラスに属するデータを破損した場合に発生する微妙なエラーを防ぐことができます。

もちろん、これをあなたのケースに合わせて修正する簡単な方法は次のとおりです。

class A
{
protected:
    int data;
};

class B : public A
{
public:
    B(const A &a)
        : A(a)
    {
    }
};

int main()
{
    A a;
    B b = a;
    return 0;
}
于 2009-09-12T07:05:21.903 に答える
2

C ++標準では、保護された非静的メンバーについて次のように述べています。11.5/1

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

他の人が前述したことを修正することに加えて(コンストラクターBはプライベートです)、rlbondの方法でうまくいくと思います。ただし、標準の上記の段落の直接の結果は、メンバーポインターを使用して次のことが可能になることです。これは、もちろん、型システムの穴です。

class B : public A {
public:
  B(A &a){
    int A::*dataptr = &B::data;
    data = a.*dataptr;
  }
};

もちろん、このコードの実行は推奨されていませんが、本当に必要な場合はアクセスできることを示しています(この方法は、保護されたコンテナーメンバーにアクセスすることstd::stackで、std::queueを印刷するために使用されます) 。std::priority_queuec

于 2009-09-12T10:48:52.583 に答える
1

コンストラクターでオブジェクトをコピーするべきではありません。目的は、のメンバーの初期化をそれ自体のコンストラクターに任せることです。ABA

struct A { 
  A( const A& a ): data( a.data ) {}
  protected: int data; 
};

struct B : public A {
  B( const A& a ): A( a ) {}
};
于 2009-09-12T11:18:18.503 に答える
0

Bのコンストラクターはプライベートです。クラスで何も指定しない場合、デフォルトの修飾子はprivateです(構造体の場合はpublicです)。したがって、この例では、Bを作成できないという問題があります。コンストラクターBにpublicを追加すると、次のような問題が発生します。

Bは、Aの一部を変更する権利を持っていますが、この場合のように別のAを変更することはできません。

次のことができます:

class A
{
public:
  A()
      : data(0)
  {
  }
  A(A &a)
  {
    data = a.data;
  }
protected:
  int data;
};

class B : public A
{
public:
  B(A &a)
      : A(a)
  {
  }
};

int main()
{
  A a;
  B b = a;
  return 0;
}
于 2009-09-12T06:59:52.260 に答える