親クラスの保護されたデータは子クラスでは使用できませんか?

StackOverflow https://stackoverflow.com/questions/1414506

  •  06-07-2019
  •  | 
  •  

質問

私は混乱しています:保護されたデータは、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'

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

役に立ちましたか?

解決

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

  

派生クラスは基本クラスにアクセスできます’独自の型のオブジェクトのみの保護されたメンバー....これにより、1つの派生クラスが他の派生クラスに属するデータを破損した場合に発生する微妙なエラーが防止されます。

もちろん、これをケースに合わせて修正する簡単な方法を次に示します。

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;
}

他のヒント

C ++標準では、 11.5 / 1

の保護された非静的メンバーについて記述されています
  

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

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

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

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

にアクセスする>

B コンストラクタ内の A オブジェクトをコピーしないでください。意図は、 A のメンバーの初期化を独自のコンストラクターに任せることです:

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

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

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;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top