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

W

William Payne

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
 
D

David Harmon

On Thu, 9 Sep 2004 16:03:24 +0200 in comp.lang.c++, "William Payne"
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/
 
W

William Payne

David Harmon said:
On Thu, 9 Sep 2004 16:03:24 +0200 in comp.lang.c++, "William Payne"
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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top