gpt4 book ai didi

c++ - 成员函数指针转换,从 Derived 到 Base 类

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:16:35 24 4
gpt4 key购买 nike

我正在做以下事情:

  • 派生类获取一个带有3个参数的成员函数指针。
  • 使用 0 个参数将其转换为来自基类的成员函数指针。
  • 将其转换为基类,返回3 个参数
  • 调用它。

它工作正常(到目前为止),但我应该保留它吗?

当前代码说明:

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;

};

查看上面类中存储的类:

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.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. 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. 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.

恕我直言,问题是 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 是一个 AView * 指向一个 DerivedView

但是当您结束将 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++ - 成员函数指针转换,从 Derived 到 Base 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32845481/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com