Closed Thread
Page 1 of 2 12 LastLast
Results 1 to 10 of 12

Thread: Derived Classes Can't Set Function Pointers

  1. #1
    Join Date
    Oct 2007
    Location
    /dev/null
    Posts
    4,513
    Blog Entries
    8
    Rep Power
    59

    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 Attached Files
    Last edited by dargueta; 10-17-2007 at 07:08 PM.

  2. CODECALL Circuit advertisement
    Join Date
    Always
    Location
    Advertising world
    Posts
    Many

     
  3. #2
    limo is offline Newbie
    Join Date
    Oct 2007
    Location
    Australia
    Posts
    14
    Rep Power
    0
    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.
    minimize->onClickEventHandler = &TitleBar::minimizeWindow;

  4. #3
    Join Date
    Oct 2007
    Location
    /dev/null
    Posts
    4,513
    Blog Entries
    8
    Rep Power
    59
    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.

  5. #4
    limo is offline Newbie
    Join Date
    Oct 2007
    Location
    Australia
    Posts
    14
    Rep Power
    0
    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.

  6. #5
    Join Date
    Oct 2007
    Location
    /dev/null
    Posts
    4,513
    Blog Entries
    8
    Rep Power
    59
    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
    }

  7. #6
    kkelly's Avatar
    kkelly is offline Learning Programmer
    Join Date
    Sep 2007
    Posts
    50
    Rep Power
    0
    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.

  8. #7
    Join Date
    Oct 2007
    Location
    /dev/null
    Posts
    4,513
    Blog Entries
    8
    Rep Power
    59
    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...

  9. #8
    kkelly's Avatar
    kkelly is offline Learning Programmer
    Join Date
    Sep 2007
    Posts
    50
    Rep Power
    0
    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.

  10. #9
    Join Date
    Oct 2007
    Location
    /dev/null
    Posts
    4,513
    Blog Entries
    8
    Rep Power
    59
    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?

  11. #10
    kkelly's Avatar
    kkelly is offline Learning Programmer
    Join Date
    Sep 2007
    Posts
    50
    Rep Power
    0
    Is Window a derived class of ConsoleObject? Could you use an implicit cast here?

Closed Thread
Page 1 of 2 12 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Similar Threads

  1. Function Pointers
    By breimer273 in forum C and C++
    Replies: 4
    Last Post: 03-16-2011, 09:30 AM
  2. Function Pointers and Inheritance
    By cod3b3ast in forum C and C++
    Replies: 3
    Last Post: 01-12-2010, 05:37 PM
  3. Function Pointers
    By marwex89 in forum C Tutorials
    Replies: 18
    Last Post: 07-09-2009, 08:45 PM
  4. function pointers
    By porno.shome in forum Pascal and Delphi
    Replies: 5
    Last Post: 07-26-2008, 12:42 AM
  5. Replies: 0
    Last Post: 08-20-2007, 11:17 PM

Tags for this Thread

Bookmarks

Posting Permissions

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