@RocketMagnet - これは、重複とラベル付けされた他の質問への回答です。私はこの質問ではなく、その質問に答えています。
一般に、メンバー関数への C++ ポインターは、クラス階層全体で移植可能にキャストできません。そうは言っても、あなたはしばしばそれで逃げることができます. 例えば:
#include <iostream>
using std::cout;
class A { public: int x; };
class B { public: int y; };
class C : public B, public A { public: void foo(){ cout << "a.x == " << x << "\n";}};
int main() {
typedef void (A::*pmf_t)();
C c; c.x = 42; c.y = -1;
pmf_t mf = static_cast<pmf_t>(&C::foo);
(c.*mf)();
}
このコードをコンパイルすると、コンパイラは次のように文句を言います。
$ cl /EHsc /Zi /nologo pmf.cpp
pmf.cpp
pmf.cpp(15) : warning C4407: cast between different pointer to member representations, compiler may generate incorrect code
$
では、「なぜ C++ には void クラスのメンバ関数へのポインタがないのですか?」この架空のすべての基本クラスにはメンバーがないため、安全に割り当てることができる値はありません! 「void (C:: )()」と「void (void:: )()」は相互に互換性のない型です。
さて、あなたは「待って、以前にメンバー関数ポインターをうまくキャストしたことがある!」と考えているに違いありません。はい、reinterpret_cast と単一継承を使用している可能性があります。これは、他の再解釈キャストと同じカテゴリにあります。
#include <iostream>
using std::cout;
class A { public: int x; };
class B { public: int y; };
class C : public B, public A { public: void foo(){ cout << "a.x == " << x << "\n";}};
class D { public: int z; };
int main() {
C c; c.x = 42; c.y = -1;
// this will print -1
D& d = reinterpret_cast<D&>(c);
cout << "d.z == " << d.z << "\n";
}
したがって、存在する場合でもvoid (void::*)()
、安全に/移植可能に割り当てることができるものは何もありません。
メンバー関数ポインターは継承階層の上下に適切にキャストされませんが、void ポインターは適切にキャストされるためですvoid (*)(void*)
。void (void::*)()
その代わり:
#include <iostream>
using std::cout;
class A { public: int x; };
class B { public: int y; };
class C : public B, public A { public: void foo(){ cout << "a.x == " << x << "\n";}};
void do_foo(void* ptrToC){
C* c = static_cast<C*>(ptrToC);
c->foo();
}
int main() {
typedef void (*pf_t)(void*);
C c; c.x = 42; c.y = -1;
pf_t f = do_foo;
f(&c);
}
それであなたの質問に。C++ がこの種のキャストをサポートしないのはなぜですか。メンバー関数へのポインター型は、既に仮想対非仮想基本クラス、および仮想対非仮想メンバー関数をすべて同じ型で処理する必要があり、一部のプラットフォームではそれらを 4*sizeof(void*) に膨張させます。メンバー関数へのポインターの実装がさらに複雑になり、生の関数ポインターはすでにこの問題をうまく解決しているためだと思います。
他の人がコメントしたように、C++ はライブラリ ライターにこれを行うのに十分なツールを提供します。その後、あなたや私のような「通常の」プログラマは、これらの詳細に汗をかくのではなく、これらのライブラリを使用する必要があります。
編集: マークされたコミュニティ wiki。C++ 標準への関連する参照を含めるように編集し、斜体で追加してください。(特に、私の理解が間違っていた標準への参照を追加してください! ^_^ )