3

次のコードを実行してみました。関数 "g" は、X では公開されているが Y では非公開である関数 "f" を呼び出していることに注意してください。

class X{
    public:
        virtual void f(void){cout<<"From X\n";}
        virtual void g(X* x) { x->f();}
};

class Y: protected X{
    private:
        void f(void){cout<<"From Y\n";}
};

int main() {
    Y y = Y();
    Y *py = &y;
    X* px = py;
    py->g(py);

    return 0;
}

出力は次のとおりです (継承が保護されていることに注意してください)。

prog.cpp: In function ‘int main()’:
prog.cpp:18:10: error: ‘X’ is an inaccessible base of ‘Y’
  X* px = py;
          ^
prog.cpp:7:16: error: ‘virtual void X::g(X*)’ is inaccessible
   virtual void g(X* x) { x->f();}
                ^
prog.cpp:19:10: error: within this context
  py->g(py);
          ^
prog.cpp:19:10: error: ‘X’ is not an accessible base of ‘Y’
prog.cpp:19:10: error: ‘X’ is an inaccessible base of ‘Y’
prog.cpp:18:5: warning: unused variable ‘px’ [-Wunused-variable]
  X* px = py;

継承を protected から public に変更すると、コードが機能し、次の出力が得られます。

From Y

継承がパブリックの場合、関数 "f" の呼び出しにプライベート アクセス制限が適用されていないように思えます (Y::f が X から呼び出されたため)。このコードを実行する前に、アクセス制限のために常にコンパイル時エラーが発生するはずだと考えていました (これは誤りであることが証明されました)。

どういうわけか、継承を public から protected に変更すると、これが修正され、Y::f への呼び出しが有効になりません。誰でも理由を説明できますか?

4

1 に答える 1

6

カプセル化が破られることはありません。メソッドは で public であり、パブリック継承を使用する場合X、クラスのオブジェクトはY「また」タイプです。X

C++ でのオーバーライドは、アクセス ルールと直交しています。パブリック メソッドをプライベート メソッドでオーバーライドできます。基本クラスへの参照を介していつでも呼び出すことができるため、おそらく悪い設計です。

これは、 へのポインタがある場合X、 のアクセス制限のみがclass X適用されることを意味します。

プライベート メソッドもオーバーライドできることに注意してください (「テンプレート メソッド」GOF デザイン パターンを参照してください)。

class X {
public:
    void f () { g (); }

private:
    virtual void g () = 0;
};

class Y : public X
{
private:
    void g () { std::cout << "from X\n"; }
};

したがって、仮想機能をできる限り非公開にすることをお勧めします。

保護された継承を使用するとコンパイルされない理由については、継承が保護されているためです。Yから非公開または保護的に継承する場合、タイプ のオブジェクトでXへのポインタを取得することはできません。XY

于 2013-10-13T07:44:11.250 に答える