Why does it insist on calling the parent's on_mdiactive() and not the child's?

Discussion in 'C++' started by William Payne, Sep 9, 2004.

  1. Hello, consider these following two classes. A base class, class
    MDIChildWindow, and a class inherting from that base class, class Document.
    In the static base member function callback() I obtain a pointer to the
    child class and call the function on_mdiactivate() using this pointer. For
    some reason, the program executes MDIChildClass::eek:n_mdiactivate() and not
    Document::eek:n_mdiactivate(). Why? on_mdiactivate() is a virtual function in
    MDIChildClass and I have redefined that function in the child class
    Document. The code contains some non-standard code (Win32-API), but, I hope
    and think, it's not an API problem I have but a problem with my classes. I
    hope you can disregard from the non-standard code, and help me solve this
    problem. If you can't I apologise and will try to create an example using
    only standard c++ that behaves exactly the same.

    The code:
    /* mdi_child_window.hpp */
    #ifndef MDI_CHILD_WINDOW_HPP
    #define MDI_CHILD_WINDOW_HPP

    #include <windows.h>
    #include <cassert>
    #include <cstring>
    #include <stdexcept>

    class MDIChildWindow
    {
    public:
    MDIChildWindow(HWND mdi_client_window,
    const char* const title,
    long lparam);

    virtual ~MDIChildWindow()
    {
    delete [] m_title;
    }

    static long CALLBACK dummy_callback(HWND mdi_child_window,
    unsigned int message,
    unsigned int wparam,
    long lparam);

    protected:

    virtual long on_mdiactivate(unsigned int /*wparam*/, long /*lparam*/)
    {
    return 0;
    }

    static const char* const m_mdi_child_class_name;

    HWND m_frame_window; /* Maybe make static? */
    HWND m_mdi_client_window; /* Maybe make static? */
    HWND m_mdi_child_window;
    char* m_title;
    };

    #endif /* #ifndef MDI_CHILD_WINDOW_HPP */

    /* mdi_child_window.cpp */
    #include "mdi_child_window.hpp"
    #include "document.hpp"

    using std::runtime_error;
    using std::strcpy;
    using std::strlen;

    const char* const MDIChildWindow::m_mdi_child_class_name =
    "MDIChildWindowClass";

    MDIChildWindow::MDIChildWindow(HWND mdi_client_window,
    const char* const title,
    long lparam)
    :
    m_mdi_client_window(mdi_client_window)
    {
    m_title = new char[strlen(title) + 1];

    strcpy(m_title, title);

    m_frame_window = GetParent(m_mdi_client_window);

    m_mdi_child_window = CreateMDIWindow(
    m_mdi_child_class_name,
    m_title,
    WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU |
    WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    mdi_client_window,
    GetModuleHandle(NULL),
    lparam /* Contains a pointer-to-class-Document */
    );

    assert(m_mdi_child_window);
    if(!m_mdi_child_window)
    {
    unsigned long error = GetLastError();

    char format_msg_str[256];

    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
    NULL,
    error,
    0,
    format_msg_str,
    sizeof(format_msg_str),
    NULL);

    MessageBox(m_frame_window, format_msg_str, "Error", MB_OK |
    MB_ICONERROR);


    delete [] m_title;
    }
    }

    long CALLBACK
    MDIChildWindow::dummy_callback(HWND mdi_child_window,
    unsigned int message,
    unsigned int wparam,
    long lparam)
    {
    switch(message)
    {
    case WM_NCCREATE:
    {
    CREATESTRUCT* cs = (CREATESTRUCT*)lparam;
    MDICREATESTRUCT* mdics = (MDICREATESTRUCT*)cs->lpCreateParams;
    Document* p = (Document*)mdics->lParam;
    assert(p);
    SetWindowLongPtr(mdi_child_window, GWLP_USERDATA, (long)p);

    return 1;
    }
    case WM_MDIACTIVATE:
    {
    Document* p = (Document*)GetWindowLongPtr(mdi_child_window,
    GWLP_USERDATA);
    assert(p);
    return p->on_mdiactivate(wparam, lparam);
    }
    default:
    {
    return DefMDIChildProc(mdi_child_window,
    message,
    wparam,
    lparam);
    }
    }
    }

    /* document.hpp */
    #ifndef DOCUMENT_HPP
    #define DOCUMENT_HPP

    #include "globals.hpp"
    #include "mdi_child_window.hpp"

    class Document : public MDIChildWindow
    {
    public:
    Document(HWND mdi_client_window,
    const char* const title);

    const HWND get_handle() const
    {
    return m_mdi_child_window;
    }

    virtual long on_mdiactivate(unsigned int wparam, long lparam);

    private:
    HWND m_frame_window;
    };

    #endif

    /* document.cpp */
    #include "document.hpp"

    Document::Document(HWND mdi_client_window,
    const char* const title)
    :
    MDIChildWindow(mdi_client_window, title, (long)this)
    {
    ;
    }

    /* This function is not called! Why?? */
    long Document::eek:n_mdiactivate(unsigned int /*wparam*/, long lparam)
    {
    // do something more than just return 0

    return 0;
    }

    / WP
     
    William Payne, Sep 9, 2004
    #1
    1. Advertising

  2. William Payne

    David Harmon Guest

    On Thu, 9 Sep 2004 16:03:24 +0200 in comp.lang.c++, "William Payne"
    <> wrote,
    >In the static base member function callback() I obtain a pointer to the
    >child class and call the function on_mdiactivate() using this pointer. For
    >some reason, the program executes MDIChildClass::eek:n_mdiactivate() and not
    >Document::eek:n_mdiactivate(). Why?


    I don't know what all that nasty API stuff is about. However, I am
    guessing that ...

    >Document::Document(HWND mdi_client_window,
    > const char* const title)
    > :
    > MDIChildWindow(mdi_client_window, title, (long)this)
    >{


    .... the callback you are asking about is all happening during the
    constructor call shown. At the time when MDIChildWindow is being
    constructed, the derived Document object has not yet been constructed
    and the type of "*this" is still a MDIChildWindow for virtual calling
    purposes.

    This issue is covered in Marshall Cline's C++ FAQ. See the topic
    "[23.3] When my base class's constructor calls a virtual function on its
    this object, why doesn't my derived class's override of that virtual
    function get invoked?" It is always good to check the FAQ before
    posting. You can get the FAQ at:
    http://www.parashift.com/c -faq-lite/
     
    David Harmon, Sep 9, 2004
    #2
    1. Advertising

  3. "David Harmon" <> wrote in message
    news:...
    > On Thu, 9 Sep 2004 16:03:24 +0200 in comp.lang.c++, "William Payne"
    > <> wrote,
    >>In the static base member function callback() I obtain a pointer to the
    >>child class and call the function on_mdiactivate() using this pointer. For
    >>some reason, the program executes MDIChildClass::eek:n_mdiactivate() and not
    >>Document::eek:n_mdiactivate(). Why?

    >
    > I don't know what all that nasty API stuff is about. However, I am
    > guessing that ...
    >
    >>Document::Document(HWND mdi_client_window,
    >> const char* const title)
    >> :
    >> MDIChildWindow(mdi_client_window, title, (long)this)
    >>{

    >
    > ... the callback you are asking about is all happening during the
    > constructor call shown. At the time when MDIChildWindow is being
    > constructed, the derived Document object has not yet been constructed
    > and the type of "*this" is still a MDIChildWindow for virtual calling
    > purposes.
    >
    > This issue is covered in Marshall Cline's C++ FAQ. See the topic
    > "[23.3] When my base class's constructor calls a virtual function on its
    > this object, why doesn't my derived class's override of that virtual
    > function get invoked?" It is always good to check the FAQ before
    > posting. You can get the FAQ at:
    > http://www.parashift.com/c -faq-lite/
    >
    >


    Thanks David, that was exactly the case. Before the constructor returned,
    four calls was made to the static callback by the system, one of these calls
    had the message WM_MDIACTIVATE which I wanted my derived class to handle.
    But since the constructor hadn't returned yet it was calling the parent
    class' on_mdiactivate() instead. You probably wont believe me now, but I
    just noticed this using a few simple print outs and was going to post about
    it when I saw your post. I "solved" this by moving the functionality from
    the derived's on_mdiactivate() to the parent. It works in this case, but
    certainly prevents reusability because what should happen in
    on_mdiactivate() will be different from each class inheriting from
    MDIChildClass. But right now I cant see how to solve this another way, I
    cant prevent the system from sending these messages and I cant make the
    constructor return any sooner. Maybe I could queue messages and wait for the
    constructor to finish but how to determine when it finishes, I dont know.

    Thanks for your reply, I will study the FAQ concerning this matter.

    / WP
     
    William Payne, Sep 9, 2004
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jeff Rodriguez
    Replies:
    23
    Views:
    1,130
    David Schwartz
    Dec 9, 2003
  2. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,976
    Smokey Grindel
    Dec 2, 2006
  3. Noozer
    Replies:
    5
    Views:
    179
    Anthony Jones
    Feb 7, 2006
  4. Noel Dolan
    Replies:
    0
    Views:
    236
    Noel Dolan
    Jul 18, 2004
  5. Bitswapper
    Replies:
    5
    Views:
    148
    Prasad, Ramit
    Aug 27, 2013
Loading...

Share This Page