Lost Password?

Go Back   CodeCall Programming Forum > Software Development > C and C++

Unregistered, Check out the Coder Battles in the Announcement and Game forums.

C and C++ C and C++ forum for discussing all forms of C except for C#. These languages are powerful low level languages used for creating Operating Systems, Device Drivers, compilers and much more.

Reply
 
LinkBack Thread Tools Search this Thread Display Modes
  #1 (permalink)  
Old 10-17-2007, 09:04 PM
dargueta dargueta is offline
Guru
 
Join Date: Oct 2007
Age: 18
Posts: 600
Last Blog:
Programs Under the Hoo...
Credits: 183
Rep Power: 11
dargueta is a jewel in the roughdargueta is a jewel in the roughdargueta is a jewel in the roughdargueta is a jewel in the rough
Default Derived Classes Can't Set Function Pointers

I'm creating a set of classes that mimic standard VC controls (such as command buttons, etc.) on the console. My base class, ConsoleObject, works beautifully. I added a few function pointers that can be set to handle events:

Code:
void (*onFocusEventHandler)(void);
void (*onLoseFocusEventHandler)(void);
void (*onClickEventHandler)(unsigned __int32 mouseX,unsigned __int32 mouseY,unsigned __int8 button);
void (*onDoubleClickEventHandler)(unsigned __int32 mouseX,unsigned __int32 mouseY,unsigned __int8 button);
void (*onMouseOverEventHandler)(unsigned __int32 mouseX,unsigned __int32 mouseY);
void (*onMouseOutEventHandler)(unsigned __int32 mouseX,unsigned __int32 mouseY);
void (*onDestroyEventHandler)(void);
Users could set the function pointers to their own function. However, when a derived class, WindowTitleBar, tries to set the function pointers, I get the following compile error:

cannot convert from 'void (__thiscall WindowTitleBar::*)(unsigned __int32,unsigned __int32,unsigned __int8)' to
'void (__cdecl *)unsigned __int32,unsigned __int32,unsigned __int8)'


Typecasting didn't work. I tried using template classes, but then the WindowTitleBar can't set the handler functions (which belong to WindowTitleBar) to the command buttons (also derived from ConsoleObject)that they're for. I get the following error:

cannot convert from 'void (__thiscall WindowTitleBar::* )(unsigned __int32,unsigned __int32,unsigned __8)' to
'void (__thiscall CommandButton::* )(unsigned __int32,unsigned __int32,unsigned __8)'


In addition, when a derived class Window tries to instantiate a variable of type WindowEventHandler which is not derived from ConsoleObject, I get illogical compile errors:

Code:
eventHandler = new WindowEventHandler(objects,this);
/*
Note that WindowEventHandler has a constructor:
WindowEventHandler(ConsoleObject<Object> **objList,ConsoleObject<Window> *parent)
*/
Causes the error:
'WindowEventHandler::WindowEventHandler(ConsoleObj ect<objClass> **,ConsoleObject<Window> *)' :
cannot convert parameter 1 from 'ConsoleObject<objClass> **' to 'ConsoleObject<objClass> **'


Last time I checked, ConsoleObject<objClass> ** and ConsoleObject <objClass> ** are the same thing.

Can someone please help me? I know this is confusing, and real GUIs are much more efficient, but I just like doing things myself and this is a major obstacle for me. I'm attaching the source code to this post. (It's a header (.h) file, but I had to change the extension to .txt to upload it.)

I have a bad habit of not documenting my code very well, so if you need further clarification, just let me know.)

Thanks in advance.
Attached Files
File Type: txt ConsoleWindow.txt (24.0 KB, 3 views)

Last edited by dargueta; 10-17-2007 at 09:08 PM.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote

Sponsored Links
  #2 (permalink)  
Old 10-23-2007, 01:40 AM
limo limo is offline
Newbie
 
Join Date: Oct 2007
Location: Australia
Posts: 14
Credits: 0
Rep Power: 0
limo is on a distinguished road
Default

Had a quick look at your code. Correct me if I'm wrong, but function members can only point to function members of the same base class or the same concrete class, and minimize and titlebar are different concrete classes, therefore this is invalid as minimize and titlebar point to different classes.
Quote:
minimize->onClickEventHandler = &TitleBar::minimizeWindow;
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #3 (permalink)  
Old 10-23-2007, 08:27 AM
dargueta dargueta is offline
Guru
 
Join Date: Oct 2007
Age: 18
Posts: 600
Last Blog:
Programs Under the Hoo...
Credits: 183
Rep Power: 11
dargueta is a jewel in the roughdargueta is a jewel in the roughdargueta is a jewel in the roughdargueta is a jewel in the rough
Default

That's what I was trying to work around. Is there any way to typecast the function to force it to work? I read something somewhere that there's a way to force the __thiscall declarator to disappear by using something like this.this->foo(). It didn't seem to help.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #4 (permalink)  
Old 10-23-2007, 08:47 AM
limo limo is offline
Newbie
 
Join Date: Oct 2007
Location: Australia
Posts: 14
Credits: 0
Rep Power: 0
limo is on a distinguished road
Default

I don't think you can. Even if it does work, it's not a safe cast. The behaviour would be unpredictable depending on the compiler. And that's bad! Best way to approach this is to use a different design. Polymorphic functions would work better.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #5 (permalink)  
Old 10-23-2007, 08:35 PM
dargueta dargueta is offline
Guru
 
Join Date: Oct 2007
Age: 18
Posts: 600
Last Blog:
Programs Under the Hoo...
Credits: 183
Rep Power: 11
dargueta is a jewel in the roughdargueta is a jewel in the roughdargueta is a jewel in the roughdargueta is a jewel in the rough
Default

I want the user to be able to specify their own functions for the handlers, so __declspec(__stdcall) __cdecl pointers would be ideal. The problem is that classes derived from ConsoleObject use the __thiscall calling convention. I'm guessing I'd use a template for the argument types...? Perhaps something like this is what you meant?

Code:
template <typename funcPtrType>
void onMouseOver(funcPtrType (*p)(void))
{
    if(p != NULL)
        (*p)();
    else
         //default handler goes here
}
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote

Sponsored Links
  #6 (permalink)  
Old 10-24-2007, 02:43 PM
kkelly's Avatar   
kkelly kkelly is offline
Learning Programmer
 
Join Date: Sep 2007
Posts: 50
Credits: 0
Rep Power: 4
kkelly is on a distinguished road
Default

In my last assignment I encountered something like your discussing.

I ended up creating a virtual base class that contained only public event functions; Basically, an interface class. Just remember to use a virtual destructor. If a class needed to handle those events, it would have to inherit the interface. For the class that called the event functions, I created a pointer (of the Interface type) and assigned it to an event handler object (instance of a derived class of the Interface Class). Then I called (raised) the event through the pointer. Like:
Code:
InterfaceClass * ptrInterfaceClass = new EventHandlingClass;
ptrInterfaceClass->SomeEvent();
You can assign an InterfaceClass * to any class that inherits the Interface class. You can used a linked list of Interface class pointers if you need add eventhandlers during run-time.
I should note that I never added asynchronous execution to the assignment, and I'm not sure how that would effect the design I used.
I hope that helps.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #7 (permalink)  
Old 10-25-2007, 06:40 PM
dargueta dargueta is offline
Guru
 
Join Date: Oct 2007
Age: 18
Posts: 600
Last Blog:
Programs Under the Hoo...
Credits: 183
Rep Power: 11
dargueta is a jewel in the roughdargueta is a jewel in the roughdargueta is a jewel in the roughdargueta is a jewel in the rough
Default

Do you mean an abstract class? I've never done that; could you show me a simple example, please? I'm a more visual person.

You'd think after programming in C++ for four years I'd have come across this before...
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #8 (permalink)  
Old 10-26-2007, 11:07 AM
kkelly's Avatar   
kkelly kkelly is offline
Learning Programmer
 
Join Date: Sep 2007
Posts: 50
Credits: 0
Rep Power: 4
kkelly is on a distinguished road
Default

Sure. I wrote this for a scenario that includes a button. When the button is pressed, it raises an event.

The abstract class is called IButtonEvents. It is the interface between the Button class and, in this instance, the SomeEventHandler class. Here is the header for IButtonEvents:
Code:
#pragma once

class IButtonEvents
{
public:

	virtual ~IButtonEvents();			//	Virtual Destructor.

	//	Purpose:	Function declaration for function thats represents an event.  Must be overridden in
	//		a derived class.
	//---------------------------------------------------------------------------------------------------
	virtual void _OnPress() = 0;		//	Is raised when a button is pressed.
};
Since I used a virtual destructor, I must provide implementation for it. Here is IButtonEvents.cpp:
Code:
#include "IButtonEvents.h"

IButtonEvents::~IButtonEvents()
{
}
I just created a class called SomeEventHandler that inherits the interface, overrides the _OnPress function and provides implementation. Here is the header for SomeEventHandler:
Code:
#pragma once
#include <iostream>
#include "IButtonEvents.h"

using namespace std;

class SomeEventHandler : public IButtonEvents
{
private:
	void _OnPress();			//	The overidden function of the inherited virtual function.
					//	AKA, the EventHandler.
};
The implementation for _OnPress just cout's the memory address of the object and identifies the function. Here is the source for SomeEventHandler:
Code:
#include "SomeEventHandler.h"

void SomeEventHandler::_OnPress()
{
	//	Display a response message identifying the object and the event.
	cout << "Object at " << this << " responding to _OnPress event." << endl;
}
For the Button class, I used a linked list of pointers, like I was talking about in the previous post. You can ignore that code. The only thing worth noting is the function AddEventHandler. Notice that an implicit conversion takes place in the parameters. Here is the header for the Button class:
Code:
#pragma once
#include "IButtonEvents.h"

class Button
{
private:

	struct EventHandlerRecord				//	The record structure for the table of EventHandlers
	{
		IButtonEvents * Object;			//	Pointer to an EventHandling object
		EventHandlerRecord * NextRecord;		//	Pointer to the next record
	};

	EventHandlerRecord * FirstRecord;			//	The pointer to the first record
	EventHandlerRecord * LastRecord;			//	The pointer to the last record

public:

	Button::Button();					//	Default Constructor
	Button::~Button();					//	Default Destructor

	//	Parameters:	A pointer to an object derived from the IButtonEvent class.
	//	Purpose:		Adds a record the EventHandler table.
	//-----------------------------------------------------------------------------------
	void AddEventHandler(IButtonEvents * EventHandlerObject);

	//	Purpose:		Raises the _OnPress event function
	//-----------------------------------------------------------------------------------
	void Press();
};
There isn't much worth noting in the source for this class, just that it calls the _OnPress function from the IButtonEvents class. Here is the source for the Button class:
Code:
#include "Button.h"

Button::Button()
{
	/*	===Initialize pointers=== */
	Button::FirstRecord = 0;
	Button::LastRecord = 0;
}
Button::~Button()
{
	/*	===Destroy the EventHandler table=== */
	
	//	create a cursor
	Button::EventHandlerRecord * cursor;

	//	while a record exists . . .
	while (Button::FirstRecord != 0)
	{
		//	. . . point the cursor to the first record
		cursor = Button::FirstRecord;
		//	move the FirstRecord to the next record
		Button::FirstRecord = Button::FirstRecord->NextRecord;
		//	delete the record at the cursor
		delete cursor;
	}
}
void Button::AddEventHandler(IButtonEvents * EventHandlerObject)
{
	//	Create a cursor
	Button::EventHandlerRecord * cursor;

	//	Create a new record
	cursor = new Button::EventHandlerRecord;
	//	Set the Object field
	cursor->Object = EventHandlerObject;

	//	If the first record hasn't been assigned yet . . .
	if (FirstRecord == 0)
	{
		//	. . . make the new record the first record
		Button::FirstRecord = cursor;
	}
	//	Else . . .
	else
	{
		//	. . . append the record to the last record
		Button::LastRecord->NextRecord = cursor;
	}
	//	Make the new record the last record
		cursor->NextRecord = 0;
		Button::LastRecord = cursor;
}
void Button::Press()
{
	/*	===Call the _OnPress function for each object in the EventHandler table===  */

	//	Create a cursor
	Button::EventHandlerRecord * cursor;

	//	Start at the first record
	cursor = Button::FirstRecord;
	//	While the cursor points to a record . . .
	while (cursor != 0)
	{
		//	. . . Call the _OnPress function for that object
		cursor->Object->_OnPress();
		//	Move to the next record
		cursor = cursor->NextRecord;
	}
}
Finally, here is main.cpp:
Code:
#include <iostream>
#include "Button.h"
#include "SomeEventHandler.h"

using namespace std;

int main()
{	
	Button myButton;							//	Button object

	SomeEventHandler * EventHandler1 = new SomeEventHandler;		//	An event handler object
	SomeEventHandler * EventHandler2 = new SomeEventHandler;		//	Another event handler object

	//	Add the EventHandlerObjects to myButton's EventHandler table
	myButton.AddEventHandler(EventHandler1);
	myButton.AddEventHandler(EventHandler2);

	//	Press the button
	myButton.Press();
	
	//	Wait for the new line character
	cin.get();

	//	Destroy the EventHandler objects
	delete EventHandler2;
	delete EventHandler1;

	return 0;
}
That's it. I believe it is a fail-safe design, excluding multiple inheritance. To support aysnchronous calls wouldn't take much work. The only drawback is that an EventHandling class has to inherit the interface, which means they must be designed to handle the events, and can't be bound during run-time. Another layer of abstraction could solve that.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #9 (permalink)  
Old 10-26-2007, 09:39 PM
dargueta dargueta is offline
Guru
 
Join Date: Oct 2007
Age: 18
Posts: 600
Last Blog:
Programs Under the Hoo...
Credits: 183
Rep Power: 11
dargueta is a jewel in the roughdargueta is a jewel in the roughdargueta is a jewel in the roughdargueta is a jewel in the rough
Default

I went with some of your suggestions, and it seems to work all right. Now I have a new problem. In my base class, ConsoleObject, there is a pointer variable called parent that is of type Window, which is declared later on in the file. The compiler chokes because it doesn't recognize the type. How can I work around this?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #10 (permalink)  
Old 10-27-2007, 01:23 PM
kkelly's Avatar   
kkelly kkelly is offline
Learning Programmer
 
Join Date: Sep 2007
Posts: 50
Credits: 0
Rep Power: 4
kkelly is on a distinguished road
Default

Is Window a derived class of ConsoleObject? Could you use an implicit cast here?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote

Sponsored Links
Reply



Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On

Similar Threads
Thread Thread Starter Forum Replies Last Post
Issue writing to file: pointer to a class which contains pointers to other classes Sheemer C and C++ 0 08-21-2007 01:17 AM
multi-pass preprocessing kenna C and C++ 11 08-14-2007 10:45 AM
Reg Fucntion pointers sowmi C and C++ 9 07-29-2007 03:29 AM
small help in this generator function plz SamehSpiky C and C++ 3 06-22-2007 11:47 AM


All times are GMT -5. The time now is 05:22 AM.

Contest Stats

Xav ........ 1097.16
MeTh0Dz|Reb0rn ........ 986.37
morefood2001 ........ 850.04
John ........ 841.93
WingedPanther ........ 684.54
marwex89 ........ 638.26
Brandon W ........ 493.36
chili5 ........ 292.12
Steve.L ........ 188.37
orjan ........ 187.41

Contest Rules

CodeCall Goal

Goal: 100,000 Posts
Complete: 79%

Ads