我有基类Object
和Event
class Object
{
//...
};
class Event
{
};
函数指针的typedef
typedef void (Object::*PF) (Event*);
一个存储两个指针的不相关的类
class Dispatcher
{
public:
Dispatcher (Object* obj, PF pf) : _obj (obj), _pf (pf)
void call (Event* event)
{
_obj->*pf (event);
}
Object* _obj;
PF _pf;
};
然后我有一个具体的对象和一个具体的事件
class ConcreteEvent : public Event
{
};
class ConcreteObject : public Object
{
public:
void handle (ConcreteEvent* event)
{
// Do something specific for ConcreteEvent
}
};
然后像这样称呼它
ConcreteObject* obj = new ConcreteObject();
Dispatcher dispatcher (obj, static_cast<PF>(&ConcreteObject::handle));
ConcreteEvent* event = new ConcreteEvent ();
dispatcher.call (event);
我保证将始终使用正确的事件调用调度程序,即,当它封装的函数指针实际需要ConcreteEvent
时,我不会调用调度程序并将其传递给SomeOtherConcreteEvent
问题是:这可以保证有效吗?在linux和mingw上,gcc 4.7当然可行。
答案 0 :(得分:4)
从C ++ 11标准,第4.11.2节:
类型为“指向cv T类型B的成员的指针”的prvalue,其中B是类类型,可以转换为 类型为“指向cv T类型D的成员的指针”的prvalue,其中D是B的派生类(第10条)。如果B是 D的不可访问(第11条),模糊(10.2)或虚拟(10.1)基类,或虚拟的基类 D的基类,需要这种转换的程序是不正确的。转换的结果是指 转换发生前与指向成员的指针相同的成员,但它指的是基数 类成员,好像它是派生类的成员。
所以是的,这应该是安全的。
编辑:所以如果你真的想要向下转换:这也是合法的,根据C ++ 11 5.2.9.12:
类型为“指向cv1 T类型D的成员的指针”的prvalue可以转换为类型为“指针”的prvalue B的类型cv2 T的成员,其中B是D的基类(第10条),如果有效的标准转换来自 “存在类型T的B成员的指针”到“指向类型T的D的成员的指针”存在(4.11),并且cv2是相同的 cv-quali fi cation,或者比cv1更高的cv-quali fi cation。 69
答案 1 :(得分:1)
我认为不是安全的,原因有两个。
第一个是指向成员函数的指针只能安全地传播向下(因为Derived
类必然从基类继承该函数,而反之则不然)
class Base {
public:
void foo();
}; // class Base
class Derived: public Base {
public:
void bar();
};
using PBase = void (Base::*)();
using PDerived = void (Derived::*)();
int main() {
PBase pb = &Base::foo;
PDerived pd = &Derived::bar;
pb = pd; // error: cannot convert 'PDerived {aka void (Derived::*)()}'
// to 'PBase {aka void (Base::*)()}' in assignment
pd = pb;
}
(见here)
第二个是你不能像那样改变参数的类型。要说明问题,请使用ConcreteObject: public virtual Object
,您会发现它无法正常工作。
现在,这并不意味着你想做的事情是不可能的,只是它需要多一点。
理想情况下,您只需修复签名即可同时使用Object
和Event
,而不是使用成员函数,然后让它处理手动转换必要的:
using Function = std::function<void(Object*,Event*)>;
void handle(Object* o, Event* e) {
ConcreteObject* co = dynamic_cast<ConcreteObject*>(o);
ConcreteEvent* ce = dynamic_cast<ConcreteEvent*>(e);
if (co and ce) { co->handle(ce); }
}
或者你喜欢的任何演员/支票。
注意:使用std::function
与lambdas / functors兼容。