简体   繁体   English

成员 function 指针和 inheritance

[英]member function pointers and inheritance

So i'm working on a simple win32 wrapper for my own convenience, and i've run into a slightly complicated problem.因此,为了我自己的方便,我正在开发一个简单的 win32 包装器,但我遇到了一个稍微复杂的问题。

this has alot of other members, but i'm omitting a bit and leaving just the offending members.这还有很多其他成员,但我省略了一点,只留下了有问题的成员。

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;

};

(for the record, Windows in this case is a namespace of various classes and objects i've made) (为了记录,Windows 在这种情况下是我制作的各种类和对象的命名空间)

just a bit nasty but lemme explain my process and reasoning.只是有点讨厌,但让我解释一下我的过程和推理。 i have a made a class called AbstractWindow which contains most of all of the functionality of a window in a very object oriented way.我制作了一个名为 AbstractWindow 的 class,它以非常面向 object 的方式包含了 window 的大部分功能。

I'm now working on a method of taking private member functions, and storing them in a map via pointers to them, which are identified by the Windows message that they are supposed to handle.我现在正在研究一种获取私有成员函数的方法,并通过指向它们的指针将它们存储在 map 中,这些函数由它们应该处理的 Windows 消息标识。 This way, when a message is received by the windows procedure, it digs through this map to see if you've installed a handler for it.这样,当 windows 过程接收到一条消息时,它会挖掘这个 map 以查看您是否为它安装了处理程序。 If it has it calls that function and exits.如果有,它会调用 function 并退出。 It it hasn't it calls DefWindowProc and exits.它没有调用 DefWindowProc 并退出。 easy enough.很容易。

However, this object is never supposed to be instantiated and is simply supposed to be inherited from and extended.然而,这个 object 永远不应该被实例化,而只是应该被继承和扩展。 problem is, that map's function pointer declaraction is of type AbstractWindow which will not allow me to store member function pointers of a type inherited from AbstractWindow.问题是,地图的 function 指针声明属于 AbstractWindow 类型,这将不允许我存储从 AbstractWindow 继承的类型的成员 function 指针。 For example,例如,

class BasicWindow : public Windows::AbstractWindow
{
public:
    BasicWindow() 
    {
         InstallHandler(WM_CREATE, &create);
    }

private:
    void Create(HWND, UINT, WPARAM, LPARAM) {}
}

... yields an error: ...产生错误:

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)'

because the pointer types are not the same, despite being inherited from the base class. So does anyone wish to suggest a solution while still maintaining this method?因为指针类型不一样,尽管是从基类 class 继承的。那么有人希望在仍然维护此方法的同时提出解决方案吗? And if not, i'm also open to suggestions that you think would make message handling more convenient than this way.如果没有,我也愿意接受您认为会使消息处理比这种方式更方便的建议。

The problem you are facing is you are trying to do the conversion in the opposite way.您面临的问题是您正试图以相反的方式进行转换。 Function pointers are contravariant in their this arguments (ie. a function pointer to a base class' function will do for a function pointer to a derived class' method, not vice versa). Function 指针在this arguments 中是逆变的(即指向基类的 function 指针 function 将对指向派生类方法的 function 指针起作用,反之亦然)。 You can:你可以:

  • just cast (with static_cast , as it is the converse of an implicit conversion).只是强制转换(使用static_cast ,因为它是隐式转换的逆过程)。 It will work fine as long as you can ensure that you never ever call the method on an inappropriate class (eg. NotABasicWindow().*method() ).只要您可以确保永远不会在不适当的 class 上调用该方法(例如NotABasicWindow().*method() ),它就可以正常工作。
  • get rid of the scheme, and register general functions (ie. anything that can be called instead of member function pointers).摆脱方案,并注册通用功能(即任何可以调用而不是成员 function 指针的功能)。 You would use eg.你会使用例如。 std::function<void(HWND, UINT, WPARAM, LPARAM)> as your handler type and registers handlers that would know their window (eg. lambda functions). std::function<void(HWND, UINT, WPARAM, LPARAM)>作为您的处理程序类型并注册知道其 window 的处理程序(例如 lambda 函数)。

    • lambda functions are a feature of C++11 . lambda 函数是 C++11 的一个特征 They roughly correspond to function objects with binders;它们大致对应function个带活页夹的对象; they create an anonymous function that can reference variables from the scope in which they are.他们创建了一个匿名的 function,它可以引用它们所在的 scope 中的变量。 An example would be一个例子是

      [=](HWND wnd, UINT i, WPARAM wp, LPARAM lp) { this->printHandler(wnd, i, wp, lp); }

      which would remember this , so it would call printHandler for the current object (current of the code creating a lambda, not invoking code) when called.它会记住this ,所以它会在调用时为当前printHandler (创建 lambda 的代码的当前代码,而不是调用代码)调用 printHandler。 Of course, the object on which the method should be invoked could be just another parameter.当然,应该调用该方法的 object 可能只是另一个参数。

      Lambdas, as well as other function objects (ie. objects that have operator() defined) can be converted to and stored as std::function objects. Lambda 以及其他 function 对象(即定义了operator()的对象)可以转换为并存储为std::function对象。

You should read up on the Curiously Recurring Template Pattern ( http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern ).您应该阅读 Curiously Recurring Template Pattern ( http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern )。

Basically, you turn your base class into a template with a template parameter that specifies the sub-class.基本上,您将基 class 转换为一个模板,其中包含一个指定子类的模板参数。

Perhaps it'll be easier to understand if you see it:如果你看到它,也许会更容易理解:

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) {}
};

Does something of this nature will work...?这种性质的东西会起作用吗……? Ps.附言。 I'd used a typedef for the function signature.我为 function 签名使用了 typedef。

BasicWindow() 
    {
         InstallHandler(WM_CREATE, reinterpret_cast<void (__thiscall Windows::AbstractWindow::* )(HWND,UINT,WPARAM,LPARAM)>(&create));
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM