30

保護されたコンストラクターに関する 1 つの質問。保護されたコンストラクターが派生クラスで使用できることを学びました。ただし、以下のコードにエラーがあることがわかりました。なぜこのようなことが起こるのですか?

class A
{
    protected:
        A(){}
};

class B: public A {
    public:
        B() {
            A* f=new A();           // Why it is not working here
        }
};
4

4 に答える 4

41

これは特にコンストラクターとは関係ありません。これがprotectedアクセスのしくみです。

protectedアクセス指定子が機能する方法では、クラスのオブジェクトがクラスのサブオブジェクトである場合にのみB、派生クラスが基底クラスのオブジェクトの内容にアクセスできます。つまり、コード内で実行できる唯一のことは、throughのコンテンツにアクセスすることです: type のポインター(または type の参照) を介してのメンバーにアクセスできます。ただし、型(または参照)のポインターを介して同じメンバーにアクセスすることはできませんA ABA BAB *B &A *A &

次の例を考えてみましょう

class A {
protected:
  int i;
};

class B : A  {
  void foo() {
    i = 0;        // OK
    this->i = 0;  // OK

    B *pb = this;
    pb->i = 0;    // OK

    A *pa = this;
    pa->i = 0;    // ERROR

    ((A *) this)->i = 0; // ERROR
  }
};

上記のでは、単純な構文を使用してB::foo基本メンバーにアクセスできます。これは、構文を使用することと同じです。ポインタには type があるため、両方とも機能します。つまり、 typeのポインタを介してアクセスしているからです。これはまさに、アクセス指定子が許可するはずのものです。ポインターを介したアクセスは、まったく同じ理由で機能します。A::iithis->ithisB *A::iB *protectedpb

thisただし、ポインターを typeに「変換」すると、以前とまったく同じメンバーにアクセスしようとしても、その新しいポインターを介してA *アクセスできなくなります。A::i

アクセス指定子をコンストラクターに適用するとprotected、非常に特殊な効果があります。保護されたコンストラクターは、基本クラスのサブオブジェクトを初期化するためにのみ使用できます。スタンドアロン オブジェクトの初期化には使用できません (これは、実行しようとしていたことです)。つまり、プロテクト コンストラクターは、C++ で抽象クラスの概念を(純粋仮想メソッドと共に) 実装するもう 1 つの方法です。クラスのコンストラクターが保護されている場合、クラスは事実上抽象です。「外部から」独立したオブジェクトを定義するために使用することはできません。(もちろん、上記は友達内だけでなく、クラス自体にも当てはまりません)。

于 2010-03-06T17:55:35.730 に答える
7

基本クラスに保護されたコンストラクターがある場合、クラスを直接インスタンス化することはできません。ただし、これを実行して、基本クラスのコンストラクターからコンストラクターを呼び出すことができます。

class A {

protected:
   A() {}
};

class B: public A {
public:
   B() : A() // allowed to access constructor like this
   {
      A* f = new A(); // Not allowed to access constructor like this!
   }
};

以下に示すようにコンストラクターを直接呼び出すと、gcc バージョン 4.1.2 で次のエラーが発生します。

      A* f = new A(); // Not allowed to access constructor like this!

test.cpp:4: error: A::A() is protected

ただし、このコンストラクターへの呼び出しではエラーは発生しません。

   B() : A() // allowed to access constructor like this

この背後にある理由は、2 番目の呼び出しが許可されている継承を介して A() コンストラクターにアクセスするためです。ただし、これは、コンストラクターを直接呼び出して、明示的に A() の新しいインスタンスを作成しようとします。

      A* f = new A(); // Not allowed to access constructor like this!

B は A から継承されているため、B は A のコンストラクターにアクセスできるはずなので、これは直感的ではないように思えるかもしれません。ただし、 C++ で保護されたコンストラクターを宣言すると、継承またはフレンド関係を使用しない限り、そのクラスのインスタンスを作成できません。

于 2010-03-06T17:19:12.790 に答える
0

私の答えを段階的に説明しましょう:

1)コンストラクターは継承されないため、派生クラスではオーバーライドできません。
2) コンストラクターが呼び出され、呼び出されません。
3) A で単純な関数を宣言し、protected void print() を宣言してから、B でそれを呼び出そうとした場合、それは機能します。これは bcoz で発生し、B はこの機能を継承しています。

4) この b : a() のようなことをすると、コンストラクターが呼び出され、それが許可されます。
5) B を A のフレンド クラスにしてから、実行して動作するかどうかを確認します。

お役に立てれば。

于 2010-03-06T18:27:47.737 に答える