簡単な答え:未定義の動作は含まれていません。表示される動作は次のとおりです。
- この式
&A::a
は、クラスAのメンバーaを指すメンバーへのポインターを取得しようとします。aがAで保護されている場合、この式はクラスA(またはAの友達)内のアクセスチェックにのみ合格します。Aから派生したクラスBでは、式を介してのみメンバーへの同じポインターを取得できます&B::a
(この式のタイプは引き続きであることに注意してくださいint A::*
)。それで:
A::a
Aで保護されている場合、式&A::a
は派生クラスBのメンバー関数で許可されていません。これはコンパイラエラーです。
- Aでpublicの場合
A::a
、この式は有効であり、memeberへのポインターを生成します。
- メンバーへのポインタをにストリーミングする
ostream
、たとえばを使用cout << &A::a
すると、が出力されます1
。これは、を呼び出した結果ostream::operator << (bool)
です。boolalphaマニピュレータを使用して、これが実際に選択されたオーバーロードであることを確認できcout << boolalpha << &A::a
ますtrue
。
- 変更された式&(A :: a)または単に&aを使用する場合、メンバーへのポインターは形成されません。ここでは、現在のオブジェクトのメンバーaのアドレス(つまり、と同じ
&(this->a)
)が取得されます。これは、intへの通常のポインターです。の基本クラスサブオブジェクトの保護されたメンバーへのこのアクセス*this
は有効であるため、aがAで保護されている場合でもバリアントを使用できます。
より長い説明:
標準によると(5.3.1 / 3):
単項&演算子の結果は、そのオペランドへのポインターです。オペランドは左辺値または修飾IDでなければなりません。オペランドが、タイプTのクラスCの非静的メンバーmに名前を付ける修飾IDである場合、結果はタイプ「タイプTのクラスCのメンバーへのポインター」を持ち、C::mを指定するprvalueになります。[...]
したがって、式&A::a
はクラスAのメンバーaへのメンバーへのポインターを取得しようとします。
次の段落(5.3.1 / 4)では、&X ::m構文のみがメンバーへのポインターを生成することを詳しく説明してい&(X::m)
ます。&m
X::m
メンバーへのポインターは、明示的な&が使用され、そのオペランドが括弧で囲まれていない修飾IDである場合にのみ形成されます。
ただし、このような式は、アクセスが許可されている場合にのみ有効です。保護されたメンバー(11.4 / 1)の場合:
非静的データメンバーまたは非静的メンバー関数がそのネーミングクラスの保護されたメンバーである場合、第11項で説明したもの以外の追加のアクセスチェックが適用されます(11.2)前述のように、保護されたメンバーへのアクセスは、参照は、あるクラスCの友人またはメンバーで発生します。アクセスがメンバー(5.3.1)へのポインターを形成する場合、ネストされた名前指定子は、CまたはCから派生したクラスを示します。[...]
あなたの場合、保護されたメンバーaへのアクセスが許可されます。これは、aへの参照がAから派生したクラスBのメンバーで発生するためです。式がメンバーへのポインターを形成しようとすると、ネストされた名前指定子(一部最後の"::a")の前はBを表す必要があります。したがって、許可される最も単純な形式は&B::a
です。このフォーム&A::a
は、クラスA自体のメンバーまたは友人内でのみ許可されます。
メンバーへのポインター用のフォーマットされた出力演算子(istreamメンバーとしてもfree演算子関数としても)がないため、コンパイラーは、標準の変換(シーケンス)を使用して呼び出すことができるオーバーロードを調べます。ポインタからメンバー、他の何かへの唯一の標準的な変換は、4.12/1で説明されています。
メンバー型への[...]ポインタのprvalueは、bool型のprvalueに変換できます。[...]nullメンバーポインタ値はfalseに変換されます。その他の値はすべてtrueに変換されます。[...]
この変換は、を呼び出すための追加の変換なしで使用できますbasic_ostream<charT,traits>& basic_ostream<charT,traits>::operator<<(bool n)
。他のオーバーロードはより長い変換シーケンスを必要とするため、オーバーロードが最適です。
一部のメンバーのアドレスを取得するため、これ&A::a
はnullメンバーポインター値ではありません。したがって、に変換されtrue
、「1」(noboolalpha)または「true」(boolalpha)として出力されます。
最後に、&(A::a)
aがAで保護されている場合でも、式はBのメンバーで有効です。上記の規則によってこの式はメンバーへのポインターを形成しないため、上記で引用した特別なアクセス規則は適用されません。このような場合、11.4/1は続きます。
他のすべてのアクセスには、(おそらく暗黙の)オブジェクト式(5.2.5)が含まれます。この場合、オブジェクト式のクラスはCまたはCから派生したクラスでなければなりません。
ここで、オブジェクトの印象は暗黙的です。(*this)
つまりA::a
、と同じ意味(*this).A::a
です。のタイプは(*this)
明らかにアクセスが発生するクラス(B)と同じであるため、アクセスが許可されます。[注:int x = A(42).a
B内では許可されません。]
つまり、 &(A::a)
withinB::show()
はと同じ意味で&(this->a)
あり、それはintへの単純なポインタです。