成员函数指针强制转换,从派生类到基类
Member function pointer cast, from Derived to Base class
我正在做以下事情:
- 从派生类获取具有3个参数的成员函数指针。
- 从基类转换为成员函数指针,0参数。
- 将的3个参数返回给基类。
- 调用。
它工作良好(到目前为止),但我应该保留它吗?
当前代码描述:
eventwarehouse用于存储和调用事件:
#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;
};
查看存储在上述类中的类:
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 ;
}
};
主: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);
}
根据c++ 11规范草案n4296, 5.2.10 Reinterpret cast [expr.reinterpret]演员]§10
如果T1和T2都是函数类型或都是对象类型,则"指向T1类型X的成员的指针"类型的右值可以显式地转换为另一类型"指向T2类型Y的成员的指针"的右值的空成员指针值(4.11)转换为目的类型的空成员指针值。此转换的结果是未指定的,除了以下情况:
-将"成员函数指针"类型的右值转换为另一个成员函数指针类型和返回到其原始类型将产生指向成员值的原始指针。
-将类型为"指向T1类型X的数据成员的指针"的右值转换为类型为"指向数据的指针"T2型Y的成员"(其中T2的对中要求并不比T1严格)返回到其原始类型将产生指向成员值的原始指针。从指向没有形参的成员函数的指针转换到具有正确形参的成员函数的指针,应返回原始指针。
IMHO,问题是fooCallback
仅在DerivedView
类上定义,因此它是而不是 AView
类的成员函数。
这是正确的:
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);
假设v
是指向DerivedView
的AView *
但是当你将void (DerivedView::*)(std::string, int, double)
转换为void (AView::*)(std::string, int, double)
时它们是不同的类型所以转换是未指定的
它可以工作,因为非静态非虚成员函数的常见实现只是一个普通(非成员)函数,其隐藏参数为this
。因此,指向成员的指针只是存储了该函数的地址,并正确地调用了指向DerivedView
的指针,给出了预期的结果。但是另一种实现也可以存储实际类型并引发异常(或做其他任何事情)。
TL/DR:当你结束从void (DerivedView::*)(std::string, int, double)
到void (AView::*)(std::string, int, double)
的转换时,你不会将指向成员的指针强制转换为其原始类型并调用未定义行为。
- 如何通过派生类函数更改基类中的向量
- 如何使用基类指针引用派生类成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如何引用基类的派生类?
- 如果基类包含双指针成员,则派生类的构造函数
- 为什么此派生对象无法访问基类的后递减方法?
- 使用基类中的派生方法运行线程,而无需使用模板
- 是否可以使用基类非虚拟方法中的派生类虚拟方法?
- C++重载函数,一个采用基类的参数,另一个采用派生类的参数
- 在派生类中使用基类的私有成员变量的最佳方法
- 基类和派生类的多态赋值运算符
- 如何在从抽象基派生的类中实现相同的方法?
- 基类的填充将被复制到派生类中
- 如何在不使用指针的情况下将派生类的对象作为参数传递给基类中的函数?
- 指向基类派生类的 std::unique_ptr 的指针
- 为什么基类数据在派生类数据之前初始化
- c++ 派生基类 Friend 函数访问父级上的私有函数
- 如何将基类替换为派生基类
- 当基类未指定构造函数时,如何使用仅具有带参数的构造函数的类派生基类?
- 解析公用派生基类模板中的函数模板名称时出错"Not declared in this scope"