IDE: Eclipse Juno; Компилятор: MinGW 4.6.2; проекта: Win32Должен ли указатель на экземпляр класса A быть статичным в классе B?
У меня есть MainWindow с двумя несколько-разнородными MDI дочерних окон: MdiChildWindowA и MdiChildWindowB. Третье дочернее окно, SharedWindow, не является MDI, но может использоваться либо дочерним окном MDI. Все они инкапсулированы в свои собственные классы C++.
Чтобы избежать распространения из SharedWindow, я позаимствовал часть одноплодной дизайн: MainWindowClass::GetSharedWindowInstance()
возвращает указатель на экземпляр SharedWindow, создавая его, если он еще не существует. MainWindow.h
включает SharedWindow* pSharedWindow
для резервного копирования функции. (Это так близко, как SharedWindow получает быть синглтоном.)
Когда MainWindow конкретизирует MdiChildWindowA и MdiChildWindowB, она проходит this
их конструкторы, которые они экономят в переменном классе pMainWindow
(определяются как MainWindow*
в MdiChildWindowA.h
и MdiChildWindowB.h
).
cout
из this
в MainWindow соответствует cout
из pMainWindow
в MDI дочернего окна конструкторах, но к тому времени еще одна функция вызывает pMainWindow->GetSharedWindowInstance()
, pMainWindow
изменилось! Создание pMainWindow
статика, похоже, решило проблему но как pMainWindow
изменить?
Кроме того, я обнаружил, что HMODULE
и LPPICTURE
переменные были статическими в SharedWindow.h
или они забыли свои значения между функциями в SharedWindow.cpp
. Являются ли типы указателей каким-то образом исключены из сохранения в качестве переменных класса? Я думал, что static
должен был обеспечить одно значение во всех экземплярах его класса.
Редактировать 2013-сентябрь-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
показывает this
является 0xdd13a0.
MainWindow создается при вызове Run(...)
, который передает указатель на экземпляр MainWindow
в lpParam
:
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
показываетявляется 0xdd13a0, когда она перешла к конструкторам MdiChildWindowA и MdiChildWindowB:
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 скопировать MainWindow
указатель в параметре pMainWindow
в переменной класса m_pMainWindow
и cout
показывает, что оба они содержат 0xdd13a0:
MdiChildWindowA::MdiChildWindowA(HINSTANCE hInstance, MainWindow* pMainWindow, ...)
{ m_pMainWindow = pMainWindow;
....
}
В WM_CREATE
процедуры окна ребенка MDI, 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
указывает на неправильно место, программа вылетает, когда функция SharedWindow
вызывается через pSharedWindow
. Однако представляется, что в этом фиктивном экземпляре MainWindow
существует GetInstanceOfSharedWindow()
, потому что возвращается адрес, но в приведенном выше коде это адрес MdiChildWindowA
!
(Примечание. Мое именование заставляет человек гайки, так что я снова набрал код с менее опасными названиями Надеются, нет опечаток.)
@brunocodutra, Hayes @ Криса: У меня нет достаточно указывает на комментарий, но я ценю ваши идеи.
Как изменилось 'pMainWindow'? Скорее всего, вы вызываете конструктор копирования, где-то вызывается, так что у вас одинаковые объекты на двух разных адресах памяти. –