所以我为了自己的方便而正在使用一个简单的win32包装器,而且我遇到了一个稍微复杂的问题。
这有很多其他成员,但我省略了一点,只留下了违规的成员。
class Windows::AbstractWindow
{
public:
void InstallHandler(UINT msgName, void (Windows::AbstractWindow::*)(HWND, UINT, WPARAM, LPARAM));
private:
std::map<UINT, void (Windows::AbstractWindow::*)(HWND, UINT, WPARAM, LPARAM)> HandlerIndex;
};
(对于记录,Windows在这种情况下是我所做的各种类和对象的命名空间)
只是有点讨厌,但是lemme解释了我的过程和推理。我有一个名为AbstractWindow的类,它以面向对象的方式包含窗口的大部分功能。我现在正在开发一种获取私有成员函数的方法,并通过指向它们的指针将它们存储在映射中,这些指针由它们应该处理的Windows消息标识。这样,当windows过程收到消息时,它会遍历此映射以查看您是否为其安装了处理程序。如果它有它调用该功能并退出。它没有它调用DefWindowProc并退出。很容易。
但是,这个对象永远不应该被实例化,而应该继承和扩展。问题是,map的函数指针声明是AbstractWindow类型,它不允许我存储从AbstractWindow继承的类型的成员函数指针。例如,
class BasicWindow : public Windows::AbstractWindow
{
public:
BasicWindow()
{
InstallHandler(WM_CREATE, &create);
}
private:
void Create(HWND, UINT, WPARAM, LPARAM) {}
}
...产生错误:
error C2664: 'Windows::AbstractWindow::InstallHandler' : cannot convert parameter 2 from 'void (__thiscall BasicWindow::* )(HWND,MSG,WPARAM,LPARAM)' to 'void (__thiscall Windows::AbstractWindow::* )(HWND,UINT,WPARAM,LPARAM)'
因为指针类型不一样,尽管从基类继承。那么有人希望在保持这种方法的同时提出解决方案吗?如果没有,我也愿意接受你认为会使消息处理比这种方式更方便的建议。
答案 0 :(得分:3)
您遇到的问题是您正试图以相反的方式进行转换。函数指针在它们的this
参数中是逆变的(即,指向基类的函数指针&#39;函数将用于指向派生类&#39;方法的函数指针,反之亦然)。你可以:
static_cast
,因为它与隐式转换相反)。只要你能确保你永远不会在不适当的类上调用该方法(例如NotABasicWindow().*method()
),它就能正常工作。摆脱该方案,并注册一般函数(即任何可以调用而不是成员函数指针的函数)。你会用eg。 std::function<void(HWND, UINT, WPARAM, LPARAM)>
作为您的处理程序类型并注册将知道其窗口的处理程序(例如,lambda函数)。
lambda functions are a feature of C++11。它们大致对应于带有粘合剂的函数对象;它们创建了一个匿名函数,可以引用它们所在范围内的变量。一个例子是
[=](HWND wnd, UINT i, WPARAM wp, LPARAM lp) { this->printHandler(wnd, i, wp, lp); }
会记住this
,因此在调用时会调用printHandler
来获取当前对象(创建lambda的代码的当前代码,而不是调用代码)。当然,应该调用该方法的对象可能只是另一个参数。
Lambdas以及其他函数对象(即定义了operator()
的对象)可以转换为std::function
个对象并存储。
答案 1 :(得分:3)
您应该阅读奇怪的重复模板模式(http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)。
基本上,您将基类转换为带有指定子类的模板参数的模板。
如果你看到它可能会更容易理解:
namespace Windows
{
template <typename T>
class AbstractWindow
{
public:
void InstallHandler(UINT msgName, void (T::*)(HWND, UINT, WPARAM, LPARAM));
private:
std::map<UINT, void (T::*)(HWND, UINT, WPARAM, LPARAM)> HandlerIndex;
};
}
class BasicWindow : public Windows::AbstractWindow< BasicWindow >
{
public:
BasicWindow()
{
InstallHandler(WM_CREATE, &BasicWindow::Create);
}
private:
void Create(HWND, UINT, WPARAM, LPARAM) {}
};
答案 2 :(得分:0)
这种性质的东西能起作用吗? PS。我使用了typedef作为函数签名。
BasicWindow()
{
InstallHandler(WM_CREATE, reinterpret_cast<void (__thiscall Windows::AbstractWindow::* )(HWND,UINT,WPARAM,LPARAM)>(&create));
}