2

基本クラスがメソッドを宣言していなくても、派生クラスのメソッドへのポインターを基本クラスのメソッドへのポインターにキャストすることは合法ですか? 、のように:

// works in VS 2008 and g++ 4.5.3
struct Base
{
};

struct Fuu : public Base
{
    void bar(){ std::cout << "Fuu::bar" << std::endl; }
    void bax(){ std::cout << "Fuu::bax" << std::endl; }
};

struct Foo : public Base
{
    void bar(){ std::cout << "Foo::bar" << std::endl; }
    void bax(){ std::cout << "Foo::bax" << std::endl; }
};

typedef void (Base::*PtrToMethod)();

int main()
{
    PtrToMethod ptr1 = (PtrToMethod) &Foo::bax;
    PtrToMethod ptr2 = (PtrToMethod) &Fuu::bax;

    Base *f1 = new Foo;
    Base *f2 = new Fuu;

    (f1->*ptr1)();
    (f2->*ptr2)();
}
4

3 に答える 3

5

ターゲット オブジェクトが反変である理由thisは、実質的に関数に渡されるパラメータであり、理論的にはパラメータが反変であるためです (関数が a を使用できる場合はBase*Derived*実際の引数として)。

ただし、任意のパラメーターの場合、基本サブオブジェクトが派生クラス レイアウトの先頭に配置されていない場合は、ポインターを調整するために shim が必要になる場合があります。メンバーへのポインターでは、ポインターのポインター調整thisが言語に組み込まれています。(このため、仮想継承を持つクラスのメンバーへのポインターは非常に大きくなる可能性があります)

于 2013-07-19T14:10:26.310 に答える
2

いいえ。これは、標準のセクション 4.11 で説明されています (私は n3337.pdf ドラフトを持っています)。

タイプ「タイプ cv T の B のメンバーへのポインター」の prvalue は、タイプ「タイプ cv T の D のメンバーへのポインター」の prvalue に変換できます。ここで、D は派生クラスです ( B の第 10 節) B が D のアクセス不能 (第 11 節)、あいまい (10.2)、または仮想 (10.1) 基本クラス、または D の仮想基本クラスの基本クラスである場合、この変換を必要とするプログラムは、形が悪い。変換の結果は、変換が行われる前のメンバーへのポインターと同じメンバーを参照しますが、基本クラスのメンバーを派生クラスのメンバーであるかのように参照します。結果は、B の D のインスタンス内のメンバーを参照します。結果は「cv T 型の D のメンバーへのポインター」型を持つため、D オブジェクトで逆参照できます。

一般に、メンバー変換へのポインターは、派生/基本クラスへのポインターとは逆の方向に機能します。(サブ) オブジェクトへのポインターは基本クラスに変換でき、メソッドへのポインターはより派生したクラスに変換できます。

関連するオブジェクトが Foo/Fuu またはそれらの派生型ではない場合に、上記のポインターのいずれかを介して呼び出そうとすると、プログラムの形式が正しくないことに注意してください。

あなたのコードはリスクを負っていると思いますが、Borland の OWL 2.0 ライブラリでは、同様のキャスト (継承が関係なくても) が頻繁に使用されていたようです。

于 2013-07-19T13:11:46.493 に答える
0

ポインターをキャストすることは正当です。使用するには、元の型にキャストし直す必要があります。根本的な問題は、関数へのポインターが派生クラスのメンバーを指していることです。そのメンバーが基本クラスのメンバーであるという保証はありません。

于 2013-07-20T13:10:00.490 に答える