23

こんにちは、次のコードにコンパイラ エラーがあります (エラーは Microsoft Visual Studio 2008 のものです)。

class B {
protected:
    int b;
};

class A : public B {
public:
    void foo() { &B::b; } 
// error C2248: 'B::b' : cannot access protected member declared in class 'B'
};

このコードにはエラーがありません:

class B {
protected:
    int b;
};

class A : public B {
public:
    void foo() { &(B::b); }
};

::演算子の優先順位に関する私の知識に基づいて、2 つのスニペットは同等に思え&ます。 )

しかし、それらは異なります...「データメンバーへのポインター」に関連するものだと思いますが、演算子の優先順位にどのように適合するかわかりません。

説明はありますか?

4

3 に答える 3

13

最初のケースでは、 pointer-to-member のアドレスを取得していますB::b。このようなポインターは親のメンバーではAなく、別のオブジェクトであるため、保護されたメカニズムを介してアクセスすることはできません。

それが機能する2番目のケースでは、の特定のインスタンスのアドレスを要求し、bその基本クラスで修飾して、多重継承の場合にコンパイラがどの基本クラスを意味するかを知るようにします。このコンテキストでは、保護された属性が表示されます。

これがコンパイルされることに注意してください。

class B
{
protected:
int b;
};

class A : public B
{
public:
void foo(){ &A::b; }  // Note here &A:: instead of &B::
};

追加の例として、次の (できればもっと馴染みのある) コードが機能しないのと同じ理由で機能しません。

class B
{
protected:
int b;
};

class A : public B
{
public:
void foo(const B* b_obj) { b_obj->b; }
};
于 2011-02-16T16:05:11.797 に答える
7

これは単なる補足です。
§5.3.1/2 は次のように述べています。

単項 & 演算子の結果は、そのオペランドへのポインターです。オペランドは、左辺値または修飾 ID でなければなりません。最初のケースで、式の型が「T」の場合、結果の型は「T へのポインター」です。...
修飾 ID の場合 ... メンバーが型 T のクラス C の非静的メンバーである場合、結果の型は「型 T のクラス C のメンバーへのポインター」です。</p>

§5.1/7 によるとB::b、qualified-id ケースに含まれますが、そうで(B::b)はありません。したがって、コンパイラはそれを左辺値として解釈します。

于 2011-02-16T17:07:43.983 に答える
6

値を返そうとすると、2 つのステートメントの違いがより明確になります。

int*     foo()    { return &(B::b);}  // This is a pointer to an int


int A::* foo()    { return &B::b; }   // This is a pointer to a member of type int

あなたがしたいことは、 A オブジェクトを介してアクセスすることです:

int A::* foo()    { return &A::b; }   // This is a pointer to a member of type int

A からと同様に、アクセスが許可されます。
外部からアクセスするように B 経由でアクセスすると、アクセス指定子がトリガーされます。

于 2011-02-16T16:12:36.190 に答える