CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 3 of 3
  1. #1
    Join Date
    May 2013
    Posts
    18

    [Concept] Automatically Attaching Objects to Parent Class

    In my program, I create controls by deriving base objects of them I've made. These controls are then are attached within the OnCreate() function via a method I've created.

    For example:
    Code:
    class tChat: public TextBox
    {
    public:
    	void OnKeyDown(UINT &KeyCode)
    	{
    		if (KeyCode == VK_RETURN)
    		{
    			MessageBox(NULL, "Pressed enter!", NULL, 0);
    			KeyCode = 0;	// Disables WM_CHAR (Removes ding sound)
    		}
    	};
    };
    
    class fMain: public Form
    {
    public:
    	void OnCreate();
    	tChat	txtChat;
    };
    
    void fMain::OnCreate()
    {
    	AddControl(txtChat);
    };
    The use of AddControl() feels quite redundant and is only their to parse a pointer to txtChat's Parent. I'm trying to see if it's possible to remove this line and automatically associate txtChat to fMain.

    Currently my hierarchy looks like:
    [User's derived Form] -> [MDIForm or Form] -> [FormBase] -> [Object]
    [User's derived Control] -> [TextBox, etc..] -> [Control] -> [Object]

    The user can then derive the Form and Controls and use their virtual OnEVENT functions to handle all the messages they expose.

    So far my first concept is using the order-of-creation based on base-class constructor's being fired to determine which object is associated with what.

    If I create a copy of a class (i.e. a Form-derived object), first the Form's constructor is fired, and then the constructor's of any class-based member-variables are fired. Is this a safe assumption? I imagine the only time this could be affected is by another thread creating the object of a Form or Control derivative?

    If this assumption is true, I could save the 'this' pointer from the FormBase constructor, and then associate it with each Control via the base Control class' constructor? Then to ensure thread-safety, I could map the current FormBase pointer to the local thread id to ensure no conflict if multiply threads are creating forms at the same time?

    I've created some mock-up code before trying to implement this into my main code. The following keeps track of the current Form being created by using a ThreadId-based map. When a control is created it gets the FormBase pointer based of it's ThreadId calling. The control then calls an Attach() function of it's parent Form using the pointer it just got, and parses a pointer to the control. The Form then adds the control's pointer to a list. When the Form eventually parses WM_CREATE, it automatically pulls the controls from the list and fires their virtual Create() functions to build them.

    Mock-up:
    Code:
    #include <Windows.h>
    #include <string>
    #include <map>
    #include <list>
    
    class FormBase;		// Forward declaration
    class FormMap;		// Forward declaration
    class Object {};	// Base Object
    
    class CSLock
    {
    public:
    	CSLock(CRITICAL_SECTION &cs) : m_CS(cs)
    	{
    		EnterCriticalSection(&m_CS);
    	};
    	~CSLock()
    	{
    		LeaveCriticalSection(&m_CS);
    	};
    
    private:
    	CRITICAL_SECTION m_CS;
    };
    
    class FormMap
    {
    public:
    	FormMap()
    	{
    		InitializeCriticalSection(&m_CS);
    	};
    	~FormMap()
    	{
    		DeleteCriticalSection(&m_CS);
    	};
    
    	void Add(FormBase *_Form)
    	{
    		CSLock Lock(m_CS);
    		m_Forms[GetCurrentThreadId()] = _Form;
    	};
    
    	FormBase *Get()
    	{
    		CSLock Lock(m_CS);
    		return m_Forms[GetCurrentThreadId()];
    	};
    
    private:
    	CRITICAL_SECTION			m_CS;
    	std::map<DWORD, FormBase *>	m_Forms;
    };
    
    FormMap		g_FormMap;	// Global FormMap
    
    class Control: public Object
    {
    public:
    	Control();
    	virtual bool Create() {return false;};
    
    private:
    	FormBase	*m_Parent;
    };
    
    class FormBase: public Object
    {
    public:
    	FormBase()
    	{
    		g_FormMap.Add(this);
    	};
    
    	void Attach(Control *_Control)
    	{
    		m_AttachedControls.push_front(_Control);
    	};
    
    private:
    	std::list<Control *>		m_AttachedControls;
    	std::map<HWND, Control *>	m_Controls;
    };
    
    Control::Control()	// Control Constructor
    {
    	m_Parent = g_FormMap.Get();
    	m_Parent->Attach(this);
    };
    
    class TextBox: public Control
    {
    public:
    	TextBox() : m_Text("") {};
    
    	const char *Text() {return m_Text.c_str();};
    	void Text(std::string _Text) {m_Text = _Text;};
    
    	virtual void OnKeyDown(UINT &) {};
    
    private:
    	std::string		m_Text;
    };
    
    class Form: public FormBase
    {
    public:
    	//	WndProc(.. WM_CREATE: ...)
    	//	{
    	//		Loop Until m_AttachedControls is empty
    	//			Control *NewControl = CurrentControlInLoop
    	//			if (NewControl->Create())
    	//				m_Controls[NewControl->m_hWnd] = NewControl;
    	//		Clear m_AttachedControls list
    	//	}
    };
    
    // ------------------------------------------------------------------------- //
    // ------------------------------------------------------------------------- //
    // #include "frzn_controls.h>
    // Code below is actual code program would use:
    // ------------------------------------------------------------------------- //
    
    class tChat: public TextBox
    {
    public:
    	void OnKeyDown(UINT &KeyCode)
    	{
    		if (KeyCode == VK_RETURN)
    		{
    			MessageBox(NULL, "Pressed enter!", NULL, 0);
    			KeyCode = 0;	// Disables WM_CHAR (Removes ding sound)
    		}
    	};
    };
    
    class fMain: public Form
    {
    public:
    	tChat	txtChat;	// Automatically Add txtChat to fMain
    };
    
    int WINAPI WinMain(HINSTANCE hThisInstance,	HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
    	fMain frmMain;
    
    	frmMain.txtChat.Text("Some message!");
    
    	MessageBox(NULL, frmMain.txtChat.Text(), NULL, 0);
    
    	return 0;
    };
    Is this plausible to use? I imagine C++ does not have many "guarantees" about how it creates objects and when. But I thought it would be safe that it would never create member-variables before the class of them is first created?

    This language is so sick!

  2. #2
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: [Concept] Automatically Attaching Objects to Parent Class

    Quote Originally Posted by FrOzeN89 View Post
    Is this plausible to use? I imagine C++ does not have many "guarantees" about how it creates objects and when. But I thought it would be safe that it would never create member-variables before the class of them is first created?
    C++ gives very clear rules about construction and destruction order (when we do not consider variables with static storage duration). The problem is that the relation you're assuming between the creation of parent and child windows is easily broken. E.g. what if you want to add some controls to a window dynamically, i.e. based on some user input. The parent already exists, but it may not be the last parent that was created.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  3. #3
    Join Date
    May 2013
    Posts
    18

    Re: [Concept] Automatically Attaching Objects to Parent Class

    Quote Originally Posted by D_Drmmr View Post
    C++ gives very clear rules about construction and destruction order (when we do not consider variables with static storage duration).
    Oh nice. I remember reading about how C++ gives no guarantees when it does something to code so I over-assumed that any hack-like stuff I do, such as relying on order-of-creation could be quite dangerous based on compiler implementations. Are there any good tutorials that anyone knows of that cover such topics about how C++ compiles without going into the full standard implementation resources? This way I could grasp a better understanding on how it all goes together. So far the tutorials I've read just say what they code does.

    Quote Originally Posted by D_Drmmr View Post
    The problem is that the relation you're assuming between the creation of parent and child windows is easily broken. E.g. what if you want to add some controls to a window dynamically, i.e. based on some user input. The parent already exists, but it may not be the last parent that was created.
    I have a few options here I think. Probably best I add both.

    1. I could modify the AddControl() to disable the auto-control assignment as this function would only be used for dynamically adding controls.

    2. I already have a template wrapper function called CreateForm() that belongs to a parent App class. It is the only way a derived-(MDI)/Form should be created with my class. You simply declare a pointer of your derived-(MDI)Form and parse that pointer to CreateForm(). It does the new and automatically delete's it appropriately once the window is destroyed. Inside the function, after it completes the new I could then disable the auto-control assignment.

    [EDIT] Also noted, the only problem I still see here is if a more advanced custom control that I might create in the future has multiply controls on it. They could be added safely with AddControl() ignoring auto-assignment though. I might need to play around with Spy++ a bit more before I determine a solution to this, as I'm not completely sure how Windows parses WM_COMMAND messages to controls created on controls (Assuming possible. Controls on Controls was possibly in the past with VB6. Though, those controls were non-standard, etc..)
    Last edited by FrOzeN89; July 9th, 2013 at 07:09 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured