[英]Member function pointer cast, from Derived to Base class
I'm doing the following:我正在做以下事情:
It works fine (so far), but should i keep it?它工作正常(到目前为止),但我应该保留它吗?
Description of current code:当前代码说明:
EventsWarehouse is used to store and invoke events: EventsWarehouse 用于存储和调用事件:
#include <iostream>
#include <functional>
#include <unordered_map>
class EventsWarehouse
{
public:
typedef std::tuple<AView*, void (AView::*)()> box_t;
typedef std::unordered_multimap<std::string, box_t> boxes_t;
void storeEvent(std::string const &event, AView *v, void (AView::*callback)())
{
this->_events.insert(std::make_pair(event, std::make_tuple(v, callback)));
return ;
}
template<typename... Args>
bool fireEvent(std::string const &event, Args... args)
{
auto it = this->_events.find(event);
AView *v;
void (AView::*callback_)();
void (AView::*callback)(Args...);
for (; it != this->_events.end(); it++)
{
v = std::get<0>(it->second);
callback_ = std::get<1>(it->second);
/*
** CAST #2
** <void (AView::*)()>
** to
** <void (AView::*)(std::string, int, double)>
** before call
*/
callback = reinterpret_cast<void (AView::*)(Args...)>(callback_);
(v->*callback)(args...);
}
return (true);
}
private:
boxes_t _events;
};
View classes stored in the above class:查看存储在上述类中的类:
class AView
{
protected:
AView(){}
};
class DerivedView : public AView
{
public:
void fooCallback(std::string s, int i, double d)
{
std::cout << "DerivedView::fooCallback received " << s << ", " << i << ", " << d << std::endl;
return ;
}
};
Main:主要的:
int main(void)
{
DerivedView dv;
EventsWarehouse ewh;
/*
** CAST #1
** <void (DerivedView::*)(std::string, int, double)>
** to
** <void (AView::*)()>
** for storing purpose
*/
ewh.storeEvent("event 1", &dv, reinterpret_cast<void (AView::*)()>(&DerivedView::fooCallback));
ewh.fireEvent("event 1", std::string("Hello World"), 42, 84.42);
return (0);
}
According to draft n4296 for C++11 specification, 5.2.10 Reinterpret cast [expr.reinterpret.cast] §10根据 C++11 规范的 n4296 草案,5.2.10 Reinterpret cast [expr.reinterpret.cast] §10
A prvalue of type “pointer to member of X of type T1” can be explicitly converted to a prvalue of a different type “pointer to member of Y of type T2” if T1 and T2 are both function types or both object types.72 The null member pointer value (4.11) is converted to the null member pointer value of the destination type.
如果 T1 和 T2 都是函数类型或对象类型,则“指向类型 T1 的 X 成员的指针”类型的纯右值可以显式转换为不同类型的“指向类型 T2 的 Y 成员的指针”的纯右值。 72空成员指针值(4.11)被转换为目标类型的空成员指针值。 The result of this conversion is unspecified, except in the following cases:
此转换的结果未指定,但以下情况除外:
— converting a prvalue of type “pointer to member function” to a different pointer to member function type and back to its original type yields the original pointer to member value.
— 将“指向成员函数的指针”类型的纯右值转换为指向成员函数类型的不同指针并返回其原始类型会产生指向成员值的原始指针。
— converting a prvalue of type “pointer to data member of X of type T1” to the type “pointer to data member of Y of type T2” (where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer to member value.
— 将“指向类型 T1 的 X 数据成员的指针”类型的纯右值转换为类型“指向类型 T2 的 Y 数据成员的指针”(其中 T2 的对齐要求不比 T1 的对齐要求更严格)并返回到其原始类型产生指向成员值的原始指针。 the conversion to a pointer to member function with no parameters and back to a member functions with correct parameters should give back original pointer.
转换为指向没有参数的成员函数的指针并返回到具有正确参数的成员函数应该返回原始指针。
IMHO, the problem is that fooCallback
is only defined on DerivedView
class, and as such it is not a member function of class AView
.恕我直言,问题是
fooCallback
仅在DerivedView
类上定义,因此它不是类AView
的成员函数。
This would be correct:这是正确的:
void (AView::*p)() = reinterpret_cast<void (AView::*)()>(&DerivedView::fooCallback);
void (DerivedView::*callback)(std::string, int, double) =
reinterpret_cast<void (DerivedView::*)(std::string, int, double)>(p);
v->callback("Hello World"), 42, 84.42);
provided v
is a AView *
pointing to a DerivedView
提供
v
是一个AView *
指向一个DerivedView
But as you end converting a void (DerivedView::*)(std::string, int, double)
to a void (AView::*)(std::string, int, double)
they are different type so conversion is unspecified但是当您结束将
void (DerivedView::*)(std::string, int, double)
转换为void (AView::*)(std::string, int, double)
它们的类型不同,因此未指定转换
It works, because common implementation for non static non virtual member functions is simply a normal (non member) function with a hidden parameter being this
.它有效,因为非静态非虚拟成员函数的常见实现只是一个普通(非成员)函数,隐藏参数为
this
。 So the pointer to member just stores the address of that function and correctly calls it with a pointer to a DerivedView
giving expected result.因此,指向成员的指针仅存储该函数的地址,并使用指向
DerivedView
的指针正确调用它,从而给出预期的结果。 But a different implementation could also store the actual type and raise an exception (or do anything else).但是不同的实现也可以存储实际类型并引发异常(或做任何其他事情)。
TL/DR: As you end with a conversion from void (DerivedView::*)(std::string, int, double)
to void (AView::*)(std::string, int, double)
you do not cast to pointer to member to its original type and invoke undefined behaviour. TL/DR:当您以从
void (DerivedView::*)(std::string, int, double)
到void (AView::*)(std::string, int, double)
的转换结束时,您void (DerivedView::*)(std::string, int, double)
转换指向指向其原始类型的成员并调用未定义的行为。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.