@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 (C::
)()" 和 "void (void::)()" 是相互不兼容的类型。
现在,我敢打赌你正在想 "等等,我之前已经成功地转换过成员函数指针了!" 是的,你可能使用reinterpret_cast和单一继承来做到了这一点。这与其他reinterpret转换属于同一类别:
#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;
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++标准相关的参考,并将其用斜体字显示。(尤其是在我的理解有误时添加标准引用! ^_^ )
std::function
,可以通过std::bind
获得。 - Kuba hasn't forgotten Monica