2010-11-28 7 views
13

メンバー変換へのポインタに関連するC++ 03標準草案で、次の段落が見つかりました。 Bクラス型である「型CV TのBのメンバーへのポインタ」メンバー変換へのポインタ

4.11/2ポインタ型の右辺値

部材への変換は、型の右辺値に変換することができます。 DがBの派生クラス(10節)である場合、Bはアクセス不可能(11節)、あいまい(10.2)または仮想(10.1)Dの基本クラスであり、この変換を必要とするプログラムは不適切である。変換の結果は、変換前のメンバーへのポインタと同じメンバを参照しますが、基本クラスメンバを 派生クラスのメンバであるかのように参照します。結果は、DのインスタンスのBのメンバーを参照します。結果には、タイプ「Cv TのDのメンバーへのポインタ」があるため、Dオブジェクトで参照解除することができます。結果は、BのメンバーへのポインターがDのBサブオブジェクトで参照解除された場合と同じです。nullメンバー・ポインター値は、宛先タイプのNULLメンバー・ポインター値に変換されます.52)

5.2.9/9はstatic_cast

「タイプCV1 TのDのメンバーへのポインタ」型の右辺値は、「タイプCV2 TのBのメンバーへのポインタ」型の右辺値に変換することができます。 Bは、 "T型のBのメンバへのポインタ"から "T型のDのメンバへのポインタ"への有効な標準変換が存在する場合(4.11)、cv2が同じcvである場合、Dの基本クラス(10節) -資格cv1.63より大きいcv-qualification)NULLメンバー・ポインタ値(4.11)は、宛先タイプのヌル・メンバ・ポインタ値に変換されます。クラスBに元のメンバが含まれている場合、または元のメンバを含むクラスのベースクラスまたは派生クラスである場合、メンバへのポインタは元のメンバを指します。それ以外の場合、キャストの結果は未定義です。 [注意:クラスBは に元のメンバが含まれていなくても、メンバへのポインタが参照解除されるオブジェクトの動的型に元のメンバが含まれている必要があります。 5.5を参照してください。 ]

ここに私の質問があります。 5.2.9/9にあるように、4.11/2で説明した有効な変換が存在する場合、DのメンバーへのポインタはBのメンバーへのポインタに変換できます。これは、Bから継承されていないDのメンバ 'm'がある場合、メンバ 'm'へのポインタをBのメンバへのポインタの型にキャストできないことを意味しますか? 5.2.9/9のノートで

class Base { }; 
class Derived : public Base 
{ 
    int a; 
}; 
typedef int Base::* BaseMemPtr; 
BaseMemPtr pa = static_cast<BaseMemPtr>(&Derived::a); // invalid, as per 5.2.9/9 ? 

、それはまた、クラスBは、元メンバーを含む必要はないが、メンバへのポインタを逆参照されるオブジェクトの動的な型は、元のメンバを含まなければならないと言います。

私は段落の文言と混同します。上記のコードは有効ですか?

サイトを検索しましたが、同様の質問c++ inheritance and member function pointersがあります。その答えは、ポインタからベースクラスのメンバーへのポインタから派生クラスのメンバーへのポインタへの変換のみを対象としています。

+0

データメンバの値へのポインタをメンバ関数の変数へのポインタに割り当てています。それ以外の場合は、 "キャストの結果は未定義です。" – Potatoswatter

+0

ありがとう、私はそれを修正しました。 – ashen

答えて

10

あなたが書いたコードは完全に有効です。それには何も問題はありません(Derived::aがプライベートであることを除いて)。それは整形式であり、振る舞いが定義されています(これまでのところ)。標準の引用部分にあるように、明示的にstatic_castを使用してメンバポインタをアップキャストするのは完全に合法です。これはまさにあなたがやっていることです。 5.2.9/9では、尖ったメンバーがベースクラスに存在しなければならないとは決して言わない。あなたは正しく標準から引用して

また、オブジェクト内の実際のメンバーの存在は、ポインタではなく、初期の時点での間接参照の瞬間に後で必要です。これは、もちろん、メンバーアクセスオペレータ(->*または.*)の左側で使用されるオブジェクトの動的なタイプに依存します。この型は実行時にのみ認識されるため、コンパイラでチェックすることはできません。

この要件は、5.2.9/9に単なるメモとして含まれるが、オブジェクト の動的な型が含まれていない場合には、5.5/4

4でより正式な形で繰り返されますポインタが指す のメンバーは、動作は 未定義です。したがって

、例えば、あなたの例のコンテキストでコードの次の行は

Base b; 
b.*pa; // 1 

Derived d; 
d.*pa; // 2 

Base *pb = &d; 
pb->*pa; // 3 

よく形成されているオブジェクトbがメンバーを含んでいないので、最初の間接参照は、(未定義の動作を生成します)、第2と第3の両方が完全に合法です。

+0

優れた答え。しかし、私はsizeof b。* paが存在しないメンバーを参照解除しているにもかかわらず、定義された振る舞いをすることに言及することはできません。 (C++の何も単純なものではないので:-P) –

+1

@j_random_hacker:そうです。私の場合、定義されていない動作の発生は、式の*評価*中のポインタ参照解除のプロセスに結びついていますが、 'sizeof'の場合、引数は決して評価されません。 – AnT

+0

VCは、派生クラスの関数メンバへのポインタを2番目のベース型にstatic_castすると、C4407の警告を出します。したがって、標準とあなたの答えに従って、標準に準拠していません。 – ashen