Click to See Complete Forum and Search --> : Classes refer to each other


dondobert
October 19th, 1999, 08:33 AM
I created two classes, a document one and a dialog one, I need to create a member variable that contains a pointer to the other class for both of them.
To do this i need to include the declaration file (.h)of a class into the (.h) of the other and viceversa, but here i must do something wrong, since when in the dialog class i declare

public:
CMyDoc* m_pMyDoc;

i get a syntax error : missing ';' before '*'

Please let me know
Thanks

AZur
October 19th, 1999, 08:39 AM
declare the class forward during

class CMyDoc;

class CMyDialog : pubic CDialog
{
...
public:
CMyDoc* m_pMyDoc;
...

dondobert
October 19th, 1999, 08:48 AM
If i do so, i receive a:

ERROR: use of undefined type 'CMyDoc'

while compiling the (.h) of the dialog class!

AZur
October 19th, 1999, 09:01 AM
maybe you must protect your *.h - file for multiple insertion like this

#ifndef __MyClass_h__
#define __MyClass_h__

class Class1;

class MyClass : public SomeClass
{
Class1* m_pClass1;
...


}; // MyClass

#endif __MyClass_h__

October 19th, 1999, 09:22 AM
You cannot use the pointer until you have defined the class it points to.


// MyDialog.h

class CMyDoc;

class CMyDialog : public CDialog
{
public:
CMyDoc* m_pDoc;
};

// MyDoc.h

class CMyDialog;

class CMyDoc
{
public:
CMyDialog* m_pDialog;
};

// MyDialog.cpp
#include "MyDialog.h"
#include "MyDoc.h"

CMyDialog::DoSomething()
{
m_pDoc->Save();
}




The compiler is satisfied with the forward declaration since the class definition only refers to it as a pointer. To use the pointer, in DoSomething,
the class must be fully defined. Since MyDoc.h is included before DoSomething the compiler has the definition for CMyDoc.

dondobert
October 19th, 1999, 09:40 AM
Thanks a lot, it worked out perfectly!!

Tomaz Stih
October 19th, 1999, 10:10 AM
Hope you don't rate me negative because I am not solving problems but instead creating problems but a word of advice - try to avoid cyclic dependencies in classes because it makes testing difficult. Even worse then simple coupled classes (like in your case) are cycles over more then two classes, for example: a uses b uses c uses a...
You should not call functions of your dialog from your document class directly anyway since this breaks the rules of model-view interaction.

Tomaz

dondobert
October 19th, 1999, 10:19 AM
That's a good advice indeed!! But if i'm not to couple my classes, how could i have the dialog class to call a member function of my doc class?

Tomaz Stih
October 19th, 1999, 11:04 AM
Here is one way to do it. Not ideal though.
class CMyDoc : public CDocument {
public:
Subscribe(HWND hWnd, UINT uMsg) {
m_hWnd=hWnd;
m_uMsg=uMsg;
}
NotifySubscriber(WPARAM w, LPARAM l) {
::SendMessage(m_hWnd,m_uMsg,w,l);
}
private:
HWND m_hWnd;
UINT m_uMsg;
}

Then from your dialog class subscribe to event like this:
...
// dialog subscribes to event and expects WM_NOTIFYME when
// this event (for example change in document data) occurs
pMyDocument->Subscribe(this->m_hWnd, WM_NOTIFYME);
...



When data that the dialog displays changes in your document simply call NotifySubscriber. Your dialog subscribed to data giving the window message it expects when this change occurs to receive. This is a simple implementation of the observer pattern where you have only one subscriber. In MFC there already is this mechanism implemented (UpdateAllViews()) but unfortunately does not work for dialogs.
It is not a very good one since it is not type safe but implementing it type safe would mean multple inheritance for your dialog class and MFC would not like that very much.

Maybe anyone has better suggestion?

Regards,
Tomaz