是否可以授予顶级函数访问 C 中对象成员的权限?
所以我正在为 Win32 中的 GUI 编程编写一些包装类。我从一个 Window
类开始,到目前为止它包含一个 MainLoop
方法,该方法基本上是标准 Win32 WinMain
函数的克隆。这样,我们就可以执行如下操作:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow) {
Window *win = new Window();
// Do all your widget creation and add it to the window object...
return win->MainLoop(hInst, hPrev, szCmdLine, nCmdShow);
}
在窗口对象的 MainLoop 方法内,它必须通过设置其 lpfnWndProc 成员来创建新的 Win32 窗口。正如任何 Win32 程序员都知道的那样,该成员是一个指向专门定义的 WndProc
函数的函数指针。问题是,如果我要创建一个 WndProc 函数,我需要访问该窗口对象的成员(以便它知道在窗口上绘制什么等)。这给我留下了两个选择(据我所知):
我可以在顶层定义
WndProc
,但这会切断对对象成员的访问。我可以将其定义为类方法,但它不是
lpfnWndProc
要求的确切函数类型,因此我无法设置它!
谁能帮我解开这个第 22 条军规吗?
So I'm writing some wrapper classes for GUI programming in Win32. I'm starting with a Window
class, and so far it contains a MainLoop
method that is basically a clone of the standard Win32 WinMain
function. That way, one can do something like this:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow) {
Window *win = new Window();
// Do all your widget creation and add it to the window object...
return win->MainLoop(hInst, hPrev, szCmdLine, nCmdShow);
}
Inside the window object's MainLoop
method, it must create the new Win32 window by setting its lpfnWndProc
member. This member, as any Win32 programmer knows, is a function pointer to a specifically defined WndProc
function. The problem is, if I were to create a WndProc
function, I would need access to that window object's members (so that it knew what to draw on the window, etc.). This leaves me two options (that I know of):
I can define
WndProc
at the top level, but that cuts off access to the object's members.I can define it as a class method, but then it's not the exact function type that
lpfnWndProc
asks for, so I can't set it!
Can anyone help me unravel this catch-22?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您也可以将其设为静态成员函数。 :)
无论如何,解决方案取决于您是否只需要一个窗口或是否需要多个窗口。
首先是单个窗口的解决方案:
现在,如果您想允许多个窗口,请使用
std::map
(或者如果您的编译器支持std::unordered_map
)。编辑:此解决方案存在一些微妙的问题。正如 @Ben Voigt 在他的评论中指出的那样,您会遇到先有鸡还是先有蛋的问题,因为
MessageProc
在CreateWindow(Ex)
内部调用,但仅在CreateWindow(Ex)
调用您就获得了窗口句柄。这是基于 Ben 的下一条评论的解决方案(谢谢!):不过要小心,因为上面的示例不是线程安全的。您需要互斥锁窗口的创建:
以上应该是为了线程安全(我希望)。
You could also make it a static member function. :)
Anyways, a solution depends on if you need only one window or if you need multiple windows.
First a solution for single windows:
Now if you want to allow multiple windows, use a
std::map
(or if your compiler supportsstd::unordered_map
).Edit: This solution comes with some subtle problems. As @Ben Voigt points out in his comment, you get a chicken and egg problem as the
MessageProc
is called inside ofCreateWindow(Ex)
, but only after theCreateWindow(Ex)
call you have the window handle. Here's a solution based on Ben's next comment (thanks!):Be cautious though, as the above example isn't thread-safe. You need to mutex-lock the creation of the window:
The above should do for the thread-safety (I hope).
您需要创建窗口地图,当您创建新窗口时,只需将其添加到此全局地图中即可。当然,您可以使用简单的链表来代替。
You need to create window map and when you create new window just add it to this global map. You can use simple linked list instead of course.
WndProc
不能是实例成员函数,因为 Windows 不会传递任何隐藏的this
参数。它可以是命名空间范围或静态成员。一种简单的解决方案是使用
map
来查找对象,然后将参数转发到该对象的方法。请注意,
WndProc
可以维护地图本身,因为CreateWindow
提供了一个不透明的用户参数,该参数显示在WM_CREATE
中,这对于携带>Window *
,然后删除WM_DESTROY
中的条目。WndProc
cannot be an instance member function, because Windows will not pass any hiddenthis
parameter. It can be namespace scope or a static member.One simple solution is to use a
map<HWND, Window*>
to find the object, and then forward parameters to a method on the object.Note that
WndProc
can maintain the map itself, sinceCreateWindow
provides an opaque user parameter that shows up inWM_CREATE
which is useful for carrying theWindow *
, and then you remove the entry inWM_DESTROY
.将 WndProc 定义为静态类成员 - 这将与非成员函数指针(例如 Win32 编程中使用的指针)兼容(对于我所知道的所有编译器)。
但我不得不说,这有点浪费时间 - 那里有无数的 Windows 类库,而且我不认为世界真的需要另一个。
Define your WndProc as a static class member - this will then be compatible (for all compilers I'm aware of) with non-member function pointer, such as those used in Win32 programming.
But I have to say that this is a bit of a waste of time - there are a zillion Windows class libraries out there, and I don't think the world really needs another one.
听起来您需要声明该函数而不定义它。这就是原型的用途。
反过来也有可能。
Sounds you need to declare the function without defining it. That's what prototypes are for.
The other way around might also be possible.