指向类a实例的指针在类B中必须是静态的

Must a pointer to an instance of class A be static in class B?

本文关键字:静态 指针 实例      更新时间:2023-10-16

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

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

为了避免SharedWindow的扩散,我借用了单例设计的一部分:MainWindowClass::GetSharedWindowInstance()将返回一个指向SharedWindow实例的指针,如果还不存在,则创建一个。CCD_ 2包括用于备份该功能的CCD_。(这相当于SharedWindow成为一个单例。)

MainWindow实例化MdiChildWindowAMdiChildWindowB时,它将this传递给它们的构造函数,它们将其保存在类变量pMainWindow中(在MdiChildWindowA.hMdiChildWindowB.h中定义为MainWindow*)。

MainWindowthiscout与MDI子窗口构造函数中pMainWindowcout匹配,但当另一个函数调用pMainWindow->GetSharedWindowInstance()时,pMainWindow已经更改!使pMainWindow静态似乎解决了问题,但pMainWindow是如何改变的

类似地,我发现HMODULELPPICTURE变量在SharedWindow.h中是静态的,否则它们会忘记MainWindow.h0中函数之间的值指针类型作为类变量是否在某种程度上免于持久性我认为static旨在确保其类的所有实例都有一个值。

编辑2013-Sep-04:
下面是我的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显示this0xdd13a0

MainWindow是在对Run(...)的调用中创建的,该调用将指向SharedWindow* pSharedWindow0:中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显示pThis在传递给MdiChildWindowAMdiChildWindowsB的构造函数时为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:我还没有足够的评论,但我很欣赏你的想法。

如果没有完整的相关代码,很难判断,但我猜MainWindow正在被释放。我进一步猜测MainWindow最初存储在堆栈中,而不是堆中,因为导致地址更改的是函数调用(它会更改堆栈)。

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

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