【发布时间】:2013-09-07 09:40:07
【问题描述】:
IDE:Eclipse Juno; 编译器:MinGW 4.6.2; 项目:Win32
我有一个 MainWindow 和两个有点不同的 MDI 子窗口:MdiChildWindowA 和 MdiChildWindowB。第三个子窗口 SharedWindow 不是 MDI,但可以由任一 MDI 子窗口使用。所有这些都封装在自己的 C++ 类中。
为了避免 SharedWindow 的泛滥,我借用了单例设计的一部分:MainWindowClass::GetSharedWindowInstance() 将返回一个指向 SharedWindow 实例的指针,如果没有则创建一个' t 已经存在。 MainWindow.h包含SharedWindow* pSharedWindow备份功能。 (这与 SharedWindow 接近单身。)
当 MainWindow 实例化 MdiChildWindowA 和 MdiChildWindowB 时,它会将this 传递给它们的构造函数,它们保存在类变量pMainWindow 中(在MdiChildWindowA.h 和MdiChildWindowB.h 中定义为MainWindow*)。
cout of this in MainWindow 与 cout of pMainWindow 在 MDI 子窗口构造函数中匹配,但到另一个函数调用 pMainWindow->GetSharedWindowInstance() 时,pMainWindow 已更改!将pMainWindow设为静态似乎解决了问题但是pMainWindow是如何变化的呢?
同样,我发现HMODULE 和LPPICTURE 变量在SharedWindow.h 中是静态的,否则它们会忘记它们在SharedWindow.cpp 中的函数之间的值。 指针类型是否以某种方式免于作为类变量的持久性?我认为static 旨在确保其类的所有实例都有一个值。
编辑 2013 年 9 月 4 日:
下面是我的Application.cpp(主要是从教程中复制的)。我以为我的 MainWindow 实例是在堆上创建的,并且会一直存在直到退出。
#include "MainWindow.h"
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int nCmdShow )
{ MSG msg;
HWND hMdiClientWindow;
MainWindow *winMain = new MainWindow( hInstance );
if( !winMain->Run( nCmdShow ) )
{ delete winMain;
return 1;
}
hMdiClientWindow = winMain->GetMdiClientWindow();
while( GetMessage( &msg, NULL, 0, 0 ) )
{ if( ! TranslateMDISysAccel( hMdiClientWindow, &msg ) )
{ TranslateMessage( &msg );
DispatchMessage ( &msg );
}
}
delete winMain;
return msg.wParam;
}
new MainWindow(...) 调用MainWindow::MainWindow(),其中cout 显示this 是0xdd13a0。
MainWindow是在调用Run(...)时创建的,它将指针传递给lpParam中MainWindow的实例:
bool MainWindow::Run( int nCmdShow )
{ ...
hMainWindow = CreateWindowEx( ..., this );
...
}
在窗口过程中,指针保存在MainWindow的实例数据中:
LRESULT CALLBACK MainWindow::MainWindowProcedure( HWND hMainWindow, UINT Msg, WPARAM wParam, LPARAM lParam )
{ MainWindow* pThis;
if( Msg == WM_NCCREATE )
{ CREATESTRUCT* pCreateStruct = (CREATESTRUCT*) lParam;
pThis = (MainWindow*) pCreateStruct->lpCreateParams;
SetWindowLongPtr( hMainWindow, GWL_USERDATA, (LONG) pThis );
} else
{ pThis = (MainWindow*) GetWindowLongPtr( hMainWindow, GWL_USERDATA );
}
在WM_CREATE 中,cout 在传递给MdiChildWindowA 和MdiChildWindowB 的构造函数时显示pThis 为0xdd13a0:
switch( Msg )
{ ...
case WM_CREATE:
{ unique_ptr<MdiChildWindowA> upMdiChildWindowA;
unique_ptr<MdiChildWindowB> upMdiChildWindowB;
...
up_MdiChildWindowA = unique_ptr<MdiChildWindowA>( new MdiChildWindowA( m_hInstance, pThis, [window dimensions] ) );
up_MdiChildWindowB = unique_ptr<MdiChildWindowB>( new MdiChildWindowB( m_hInstance, pThis, [window dimensions] ) );
MDI子窗口的构造函数将参数pMainWindow中的MainWindow指针复制到类变量m_pMainWindow中,cout显示两者都包含0xdd13a0:
MdiChildWindowA::MdiChildWindowA( HINSTANCE hInstance, MainWindow* pMainWindow, ... )
{ m_pMainWindow = pMainWindow;
....
}
在MDI子窗口过程的WM_CREATE中,cout显示m_pMainWindow仍然包含0xdd13a0。对m_pMainWindow 的唯一其他引用出现在WM_LBUTTONDBLCLICK 中,除非我将其设为静态,否则它会以某种方式变为0xdd1380(可能在通过DefMDIChildProc(...) 的过程中?):
MdiChildWindowA::MdiChildWindowProcedure( ... )
{ ...
switch( ... )
{ ...
case WM_LBUTTONDBLCLICK:
{ SharedWindow* pSharedWindow;
...
pSharedWindow = pThis->m_pMainWindow->GetInstanceOfSharedWindow(); // pThis points to this instance of MdiChildWindowA. cout confirms its value hasn't changed.
由于m_pMainWindow 指向错误的位置,当通过pSharedWindow 调用SharedWindow 函数时程序崩溃。然而,GetInstanceOfSharedWindow() 似乎存在于 MainWindow 的这个虚假实例中,因为返回了一个地址 - 但是,在上面的代码中,它是 MdiChildWindowA 的地址!
(注意:我的命名习惯让人抓狂,所以我用不太危险的名字重新输入了代码。希望没有错别字。)
@brunocodutra、@Chris Hayes:我还没有足够的评论意见,但我很欣赏你的想法。
【问题讨论】:
-
pMainWindow发生了什么变化?您很可能导致在某处调用了复制构造函数,因此您在两个不同的内存地址处拥有相同的对象。