在B类中,指向A类实例的指针必须是静态的吗?

时间:2013-09-04 02:12:55

标签: c++ class pointers static

IDE:Eclipse Juno; 编译:MinGW 4.6.2; 项目:Win32

我有一个 MainWindow ,它有两个有点不同的MDI子窗口: MdiChildWindowA MdiChildWindowB 。第三个子窗口 SharedWindow 不是MDI,但可以由MDI子窗口使用。所有这些都封装在他们自己的C ++类中。

为了避免 SharedWindow 的扩散,我借用了单件设计的一部分:MainWindowClass::GetSharedWindowInstance()将返回一个指向 SharedWindow 实例的指针,创建一个如果一个尚不存在。 MainWindow.h包含SharedWindow* pSharedWindow备份功能。 (这与 SharedWindow 一样接近单身人士。)

MainWindow 实例化 MdiChildWindowA MdiChildWindowB 时,它会将this传递给它们的构造函数,并将它们保存在类变量中{ {1}}(在pMainWindowMainWindow*中定义为MdiChildWindowA.h)。

MainWindow MdiChildWindowB.h的{​​{1}}与MDI子窗口构造函数中cout的{​​{1}}匹配,但是当另一个函数调用{时{1}},this已发生变化!让cout静态似乎解决了问题pMainWindow是如何改变的?

同样,我发现pMainWindow->GetSharedWindowInstance()pMainWindow变量在pMainWindow中是静态的,或者他们会忘记pMainWindow中函数之间的值。 指针类型是否以某种方式免于持久性作为类变量?我认为HMODULE旨在确保其类的所有实例中的一个值。

编辑2013年9月4日:
下面是我的LPPICTURE(主要是从教程中复制而来)。我以为我的SharedWindow.h实例是在堆上创建的,并且会一直存在直到退出。

SharedWindow.cpp

static调用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; } 0xdd13a0

MainWindow 是在对new MainWindow(...)的调用中创建的,该调用将指针传递给MainWindow::MainWindow()cout的实例:

this

在窗口过程中,指针保存在 MainWindow 的实例数据中:

Run(...)

MainWindow中,lpParam显示bool MainWindow::Run( int nCmdShow ) { ... hMainWindow = CreateWindowEx( ..., this ); ... } 0xdd13a0 ,当它传递给 MdiChildWindowA MdiChildWindowB的构造函数时

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

MDI子窗口的构造函数将参数WM_CREATE中的cout指针复制到类变量pThis中,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] ) ); 显示两者都包含 0xdd13a0

MainWindow

在MDI子窗口过程的pMainWindow中,m_pMainWindow显示cout仍然包含 0xdd13a0 。对MdiChildWindowA::MdiChildWindowA( HINSTANCE hInstance, MainWindow* pMainWindow, ... ) { m_pMainWindow = pMainWindow; .... } 的唯一其他引用发生在WM_CREATE中,除非我已将其设为静态,否则它会以某种方式变为 0xdd1380 (可能在通过cout期间?):

m_pMainWindow

由于m_pMainWindow指向错误的位置,因此当通过WM_LBUTTONDBLCLICK调用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实例中存在SharedWindow,因为会返回一个地址 - 但是,在上面的代码中,它是pSharedWindow的地址!

(注意:我的命名约定驱使人们疯狂,所以我用不太危险的名字重新输入代码。希望没有错别字。)

@brunocodutra,@ Chris Hayes:我还没有足够的评论意见,但我很感激你的想法。

1 个答案:

答案 0 :(得分:0)

没有完整的相关代码很难说,但我猜想 MainWindow 正在被取消分配。我会进一步猜测 MainWindow 最初是存储在堆栈中而不是堆中,因为导致地址改变的是函数调用(它改变了堆栈)。

我的建议:验证 MainWindow MdiChildWindowA MdiChildWindowB (不确定哪些 pMainWindow 更改)是本地变量,如果是这样,请更改您的代码,以便它们在堆中分配,即通过使用关键字 new 进行动态分配。

回答第二个问题,指针与其他任何类型都没有区别对待,本质上它们非常像整数,但它们的内容很快被解释为内存地址。