2013-09-04 1 views
0

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 @ Криса: У меня нет достаточно указывает на комментарий, но я ценю ваши идеи.

+3

Как изменилось 'pMainWindow'? Скорее всего, вы вызываете конструктор копирования, где-то вызывается, так что у вас одинаковые объекты на двух разных адресах памяти. –

ответ

0

Трудно сказать без полного соответствующего кода, но я бы предположил, что MainWindow освобождается. Я бы предположил, что MainWindow является оригинальным, хранящимся в стеке, а не кучей, потому что причиной изменения адреса является вызов функции (который изменяет стек).

Мой совет: проверить, если либо MainWindow или MdiChildWindowA и MdiChildWindowB (не уверен, pMainWindow изменения) являются локальными переменными, и если да, то изменить код, так что они получают выделяется в куче, т.е. динамичность с использованием ключевого слова .

Отвечая на второй вопрос, указатели обрабатываются иначе, чем любые другие типы, по сути, они очень похожи на целые числа, но их содержимое сразу же можно интерпретировать как адреса памяти.

Смежные вопросы