[英]Is it possible to give a top-level function access to an object's members in 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
要求的确切函数类型,所以我无法设置它!
有人可以帮我解开这个catch-22吗?
您也可以使其成为静态成员函数。 :)
无论如何,一种解决方案取决于您只需要一个窗口还是需要多个窗口。 首先是单个窗口的解决方案:
// in .h
class Window{
public:
static LRESULT WINAPI MessageProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT InternalMessageProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// ...
};
// in .cpp
#include "Window.h"
Window* global_window = 0;
Window::Window(/*...*/){
if(!global_window)
global_window = this;
else
// error or exception... or something else
}
LRESULT WINAPI Window::MessageProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
return global_window->InternalMessageProc(hWnd, msg, wParam, lParam);
}
现在,如果要允许多个窗口,请使用std::map
(或如果编译器支持std::unordered_map
)。
编辑 :此解决方案带有一些细微的问题。 正如@Ben Voigt在他的评论中指出的那样,由于MessageProc
在CreateWindow(Ex)
内部被调用,您遇到了一个鸡与蛋的问题,但是只有在CreateWindow(Ex)
调用之后,您才拥有窗口句柄。 这是基于Ben的下一条评论的解决方案(谢谢!):
// Window.h stays the same
// in .cpp
#include "Window.h"
#include <map>
std::map<HWND, Window*> window_map;
Window* currently_created_window = 0;
Window::Window(){
currently_created_window = this;
window_handle = CreateWindow(/*...*/);
}
LRESULT WINAPI Window::MessageProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
// if the key 'hWnd' doesn't exist yet in the map
// a new key-value pair gets created and the value gets value-initialized
// which, in case of a pointer, is 0
if(window_map[hWnd] == 0){
// window doesn't exist yet in the map, add it
window_map[hWnd] = currently_created_window;
}
window_map[hWnd]->InternalMessageProc(hWnd, msg, wParam, lParam);
}
但是请谨慎,因为上面的示例不是线程安全的。 您需要互斥锁定窗口的创建:
Window::Window(/*...*/){
Lock lock_it(your_mutex);
currently_created_window = this;
window_handle = CreateWindow(/*...*/);
lock_it.release();
// rest of the initialization
}
上面应该做的线程安全(我希望)。
您需要创建窗口地图,并在创建新窗口时将其添加到此全局地图中。 您可以使用简单的链接列表来代替课程。
map<HWND, Window *> wndmap;
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{
Window *pWnd = wndmap [hwnd];
....
}
WndProc
不能是实例成员函数,因为Windows不会传递任何隐藏的this
参数。 它可以是名称空间范围或静态成员。
一种简单的解决方案是使用map<HWND, Window*>
查找对象,然后将参数转发给该对象上的方法。
请注意, WndProc
可以维护地图本身,因为CreateWindow
提供了一个不透明的用户参数,该参数显示在WM_CREATE
,这对于携带Window *
很有用,然后您删除WM_DESTROY
中的条目。
将WndProc定义为静态类成员-这样,它将与非成员函数指针(例如Win32编程中使用的那些)兼容(对于我知道的所有编译器)。
但是我不得不说这有点浪费时间-那里有无数的Windows类库,而且我认为世界上真的不需要另一个。
听起来您需要在不定义函数的情况下声明该函数。 那就是原型的目的。
class Object;
void f(Object* o);
class Object {
public:
...
void some_method() {
... &f ...
}
void another_method() {
...
}
...
};
void f(Object* o) {
...
o->another_method();
...
}
另一种可能的方式也是可能的。
class Object {
public:
...
void some_method();
void another_method();
...
};
void f(Object* o) {
...
o->another_method();
...
}
void Object::some_method() {
... &f ...
}
void Object::another_method() {
...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.