4

次の単純なコードは VC2008 でコンパイルされますが、g++ はコードを拒否します。

#include <iostream>

class myclass
{
protected:
    void print() { std::cout << "myclass::print();"; }
};

struct access : private myclass
{
    static void access_print(myclass& object)
    {
        // g++ and Comeau reject this line but not VC++
        void (myclass::*function) () = &myclass::print;

        (object.*function)();
    }
};

int main()
{
    myclass object;
    access::access_print(object);
}

(/W4)VC でオンになっていますが、警告は表示されません。

g++ 4.4.1 でエラーが表示されます:

correct.cpp: In static member function ‘static void access::access_print(myclass&)’:
correct.cpp:6: error: ‘void myclass::print()’ is protected

g++ が正しい場合、クラスの保護されたメンバーにアクセスするにはどうすればよいですか? 別の方法はありますか?


@Suroot type のオブジェクトを渡してはいけないということmyclassですか?実際には問題ではありません.g ++は同じエラーを出しますが、VCは警告なしでコードをコンパイルします.

#include <iostream>

class myclass
{
protected:
    void print() { std::cout << "myclass::print();"; }
};

struct access : private myclass
{
    static void access_print()
    {
        myclass object;
        void (myclass::*function) () = &myclass::print;

        (object.*function)();
    }
};

int main()
{
    access::access_print();
}
4

3 に答える 3

13

正解です。標準の関連部分は上で引用されていますが、その価値の根拠は次のとおりです。

C++の のセマンティクスはprotected、「このメンバーは、このクラスまたは任意の派生クラスのメソッドからアクセスできますが、アクセスされるオブジェクトの動的な型が の型と同じである、またはその型から派生していることが保証されている場合に限り *thisます」という意味です。

後者のビットはあまり明白ではないかもしれないので、ここに例を示します:

 class Base {
 protected:
     int X;
 };

class Derived : public Base {
   void Foo(Base* b, Derived* d) {
       this->X = 123; // okay - `this` is definitely either Derived
                      // or inherited from Derived

       d->X = 456;    // also okay, for the same reason

       b->X = 789;    // NOT OKAY; b could point to instance of some other class
                      // Derived2, which isn't inherited from Derived!
   }
};

これは設計によるものです。つまりDerived2、保護されたメンバーをどのように処理するか (不変条件など) について独自の意見を持つことができ、それは厳密にそれとその基本クラス (およびその派生クラス) の間である必要がありますが、そのフィールドを作成して非表示にしないことにした場合private)。クロス階層アクセスは、基本クラスが事前に階層全体を決定することを事実上意味するため、このモデルに反します。深い階層の上にある非常に抽象的なクラスの場合、これは望ましくない場合があります。

ここで、特定の問題に戻ります。今ではかなり明白なはずです。メンバー関数ポインターを取得したら、そのポインターが指す関数を、一致する型の任意のレシーバーで呼び出すことができます。基本クラスの保護されたメソッドの場合、これは、(自分のクラスではなく) 基本クラスに型指定されたメソッドへのポインターを取得できる場合、それを呼び出して、自分とは異なる型へのポインターを渡すことができることを意味します。クラス (またはそれから派生) であり、上記で概説した保護されたアクセスのルールに違反しています。したがって、これを行うことは許可されていません。

于 2009-11-24T04:10:41.227 に答える
6

g++ と comeau は正しいと思います。保護されたメンバーの指定子は、「アクセス」型または派生型でなければならないため、コードは次のようになります。

void (myclass::*function) () = &access::print;

コンパイルします。

これは11.5.1が原因だと思います:

…アクセスの場合【編】保護されたメンバーへ] はメンバーへのポインターを形成するためのものであり、nested-name-specifier は派生クラス (またはそのクラスから派生した任意のクラス) に名前を付けるものとします。

于 2009-11-24T03:54:06.597 に答える
2

オブジェクトはパラメーターとして渡されるため、プライベート/保護された関数に直接アクセスすることはできません。

編集:myclassをオブジェクトに変更

于 2009-11-24T03:50:02.503 に答える