9

これが私を悩ませるコードのサンプルです:

class Base {
  protected:
    virtual void foo() = 0;
};

class Derived : public Base {
  private:
    Base *b; /* Initialized by constructor, not shown here
                Intended to store a pointer on an instance of any derived class of Base */

  protected:
    virtual void foo() { /* Some implementation */ };
    virtual void foo2() {
      this->b->foo(); /* Compilator sets an error: 'virtual void Base::foo() is protected' */
    }
};

保護されたオーバーライドされた関数にどのようにアクセスしますか?

ご協力いただきありがとうございます。:o)

4

6 に答える 6

11

基本クラスの保護されたメンバーには、現在のオブジェクトからのみアクセスできます。
したがって、を呼び出すことは許可されてthis->foo()いますが、を呼び出すことは許可されていませんthis->b->foo()。これはDerived、の実装を提供するかどうかとは無関係ですfoo

この制限の背後にある理由は、そうでなければ保護されたアクセスを回避することが非常に簡単になるためです。のようなクラスを作成すると、突然、部外者がアクセスできないはずだったDerived他のクラスの一部(のような)にもアクセスできるようになります。OtherDerived

于 2011-01-12T19:04:58.187 に答える
6

通常Base::foo()は、現在のインスタンスの基本クラスを参照するを使用して行います。

ただし、コードが意図したとおりに実行する必要があり、許可されていない場合は、foo()を公開するか、DerivedをBaseのフレンドにする必要があります。

于 2011-01-12T18:26:22.463 に答える
3

Base1つの解決策は、呼び出しをプライベート/保護された関数(例では)にリダイレクトする静的保護された関数を宣言することfooです。

まあ言ってみれば:

class Base {
protected:
    static void call_foo(Base* base) { base->foo(); }
private:
    virtual void foo() = 0;
};

class Derived : public Base {
private:
    Base* b;
protected:
    virtual void foo(){/* Some implementation */};
    virtual void foo2()
    {
        // b->foo(); // doesn't work
        call_foo(b); // works
    }
};

このように、カプセル化を破ることはありません。なぜなら、の設計者は、パブリックインターフェイスに入れたり、すべての可能なサブクラスを明示的に友達に変えたりすることを避けながら、すべての派生クラスが相互Baseに呼び出すことを許可する明示的な選択を行うことができるからです。foofooBase

また、このメソッドfooは、仮想であるかどうか、またはプライベートであるか保護されているかに関係なく機能します。

上記のコードの実行中のバージョンへのリンクと、もう少しビジネスロジックを備えた同じアイデアの別のバージョンがあります

于 2016-10-24T10:19:32.923 に答える
1

少し壊れやすいですが、ここで定義したクラスでは、これは機能しませんか?

virtual void foo2() {
  reinterpret_cast<Derived *>(this->b)->foo(); 
}

reinterpret_castは、ベースオブジェクトのVTABLEをポイントし、このメンバーアクセサーを介してそれを呼び出します。

于 2013-09-10T09:09:58.117 に答える
0

スコープ演算子(Base :: foo())を使用して、ベース関数を明示的に呼び出します。this->b->foo();ただし、この場合、Baseクラスはfoo(純粋な仮想)を定義していません。したがって、bはBaseへのポインターであり、Derivedではないため、実際には実行する関数はありません。

于 2011-01-12T18:31:40.017 に答える
0

保護されたオーバーライドされた関数にどのようにアクセスしますか?

- - どこから?

保護されたメンバーには、(同じクラスのメソッドを除いて)継承を介してのみアクセスできます。たとえば、class Derived1から継承するがDerivedあり、のオブジェクトがDerived1を呼び出すことができるとしますfoo()

編集:保護されたアクセス指定子に関するMSDNの記事。

于 2011-01-12T18:49:40.053 に答える