2011-08-16 10 views
0

メンバ変数へのポインタを多態的に使用しようとしています。メンバ変数へのポリモーフィックポインタ

この作品:

struct Foo 
{ 
    int member0; 
    int member1; 

    int* getMember(int i) 
    { 
    static int Foo::* table[2] = { &Foo::member0, &Foo::member1 }; 
    return &(this->*table[i]); 
    } 
}; 

メンバーが同じタイプ(BaseClassの)ではないので、これはない:

struct Foo 
{ 
    SubClassA member0; 
    SubClassB member1; 

    BaseClass* getMember(int i) 
    { 
    static BaseClass Foo::* table[2] = { &Foo::member0, &Foo::member1 }; 
    return &(this->*table[i]); 
    } 
}; 

グラム++によって報告されたエラーがある:

[...] invalid conversion from 'SubClassA Foo::*' to 'BaseClass Foo::*' 
[...] invalid conversion from 'SubClassB Foo::*' to 'BaseClass Foo::*' 

この作業を行う方法はありますか?つまり、基本クラスへのメンバーポインタを "アップキャスト"する方法はありますか?

+1

質問の形式は本当に悪いです。あなたのコードで何が問題になっていますか?エラーはありますか?あなたがしたいこと、そしてあなたが直面している問題を投稿してください。 – Nawaz

+0

@Nawazええ、私はほとんどこの質問に答えようとしましたが、彼が何をしたいのか、何が間違っていたのかは分かりませんでした。 –

+0

私はエラーメッセージといくつかの説明を追加しました。 – hmn

答えて

1

これはできません。複数の継承のため、ベースアドレスは必ずしも派生アドレスと同じではありません。あなたは、あるものを他のものに変換するためにいくつかの隠しアドレス調整魔法が必要であり、非常に単純なオブジェクト(基本的に整数オフセット)であるメンバへのポインタはこの魔法に対応できません。

アドレス調整が必要な場合があり、必要でない場合は、原則としてメンバーへの多態ポインタを許可することができます。しかし、これは単純さと一貫性のために行われていません。

ポインタへのポインタの代わりに、Foo *を受け入れてBaseClass *を返す関数(または関数のようなオブジェクト)へのポインタを使用できます。あなたは、しかし、各メンバーのための別の機能を作る必要があります。

+0

Cの' '(BaseClass Foo :: *)&Foo :: member0'を使用してこれをハックすることができるようです。私は、これらのメンバ型で多重継承は使用されていないと主張できます...しかし、おそらく代わりにBaseClassポインタの配列を使うことに変わります。 – hmn

+0

@hmnなんで?有用な定義されたキャストが見つからなければ、それは 'reinterpret_cast'にまで崩壊するでしょう。逆参照は、ほんの少数の場合を除いて未定義の振る舞いです逆参照の前に_back_をキャストしておくと残りの部分は「有用」に過ぎません)...これは許可されている例ではありません。コンパイラがちょうどこの時間に働いたことができた最も驚くべきことをやったという事実は、これをまったく良いアイデアにはしません。そうではありません。 –

0

簡単な方法は、メンバーのデータポインタをすべてスキップすることです。堅牢性については

getMember(int i) { 
    BaseClass* ptr[2] = { &member0, &member1 }; 
    return ptr[i]; 
} 
+0

これは簡単ですが、遅くなるでしょうか?静的ポインタを使ってそれを行う理由は、参照時間を最小限に抑えることです... – hmn

+1

@hmn:コンパイラが生成するものに驚くかもしれない小さな関数のアセンブリを見たいのですが... –

+0

その関数はメンバー数が少ないときは小さく; – hmn

1
BaseClass* getMember(const int i) 
{ 
    switch(i) 
    { 
    case 0: return &member0; 
    case 1: return &member1; 
    default: throw <exception>; 
    } 
} 

あなたはi範囲または0と1の範囲内であれば、とにかくチェックしなければなりません。この単純化されたアプローチについて考えることができます。

関連する問題