Jump to content
  • Advertisement
Sign in to follow this  
Jan K

Calling Functionpointers to Memberfunctions of a derived class.

This topic is 4265 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Well, the title says it all :D What i'd like to do: I have a class A and a derived class B. In B i declare a function with a given signature (ie. void f (obj*)). Now i want to register this function through a function declared in A, so that some other function of A is able to call the function, that was actually declared in B. typedef void (A::*MFP) (void); class A { void RegisterFunction (MFP p) ... void DoSomeNastyStuff (void) {.... calls all the registered functions ... } } class B : public A { B (void) { RegisterFunction (f); } void f (void) {...} } I can't just use virtual functions, because at compile-time of A it is not known, what functions are required. I need to use member-functions, because the functions need to change the state of the classes and it would be nice, if those functions to register could be virtual. Now the thing is, i don't believe this is possible. HOWEVER, actually nVidias Scenegraph SDK does EXACTLY that! I poked a bit in the code and found this: typedef void (BASECLASS::*PMFN) (); //!< pointer to member function type template<typename U> inline void MemFunTbl::addEntry (size_t i, U pmfn) { // register function pointer if ( m_ftbl.size() <= i ) { // add 32 table entries m_ftbl.resize(i+0x20, NULL); } m_ftbl=*(PMFN*)&pmfn; } As you can see, they register a memberfunction pointer, by casting it into a pointer to the function, then casting that pointer to the functionpointer into a pointer to a functionpointer of the baseclass, and then dereferencing that to a functionpointer to the baseclass. Pretty nasty, but the compiler does not complain. Now in the base-class, they call that function somewhere, and the code looks like this: (this->*(void (Traverser::*)(const nvsg::Object*))(*m_mftbl)[oc]) (object); Well, in general they just take the memberfunctionpointer, cast it into a functionpointer to a function that returns void and takes some argument and call that on the baseclass. So far so good, but when i do the same in my code, my application just crashes when trying to call a function through a function pointer, that had to go through this procedure. If anyone knows more about this and might be able to give me some advice, i'd like to here it. If you have a completely different idea, how to solve the same problem, that would be even more interessting. Thanks, Jan.

Share this post


Link to post
Share on other sites
Advertisement
Search around for 'functors'. You'll have to use a bit of template trickery to get member function callbacks to work. I think the boost library might have something as well, but you'll have to search around for some more info.

Share this post


Link to post
Share on other sites
This can be done without too much hassle:

#include <list>
#include <iostream>
using namespace std;

//=============================================
// NOTE: This code does not clean up allocated
// resources!
//=============================================

//=============================================
// Base Class
//=============================================

class A
{
public:
//=============================================
// This class is used to allow class A to
// access derived classes instantiations.
class GenericFunctionList
{
public:
virtual void CallAllFunctions (A *base) = 0;
};

protected:
//=============================================
// Class to hold list of functions to call
// You need to instantiate this for each
// derived class
template <typename T>
class FunctionList : public GenericFunctionList
{
public:
typedef void (T::*FnCallback) (void);

void AddFunction (FnCallback function)
{
m_function_list.push_back (function);
}

private:
typedef list <FnCallback> FunctionCallbackList;

virtual void CallAllFunctions (A *base)
{
T
*derived = reinterpret_cast <T *> (base);

for (FunctionCallbackList::iterator it = m_function_list.begin (), end = m_function_list.end () ; it != end ; ++it)
{
(derived->*(*it)) ();
}
}

FunctionCallbackList
m_function_list;
};

typedef list <GenericFunctionList *> Functions;

public:
//=============================================
// Call all registered functions
void CallAllFunctions (void)
{
for (Functions::iterator it = m_functions.begin (), end = m_functions.end () ; it != end ; ++it)
{
(*it)->CallAllFunctions (this);
}
}

protected:
Functions
m_functions;
};

//=============================================
// Derived Class
//=============================================

class B : public A
{
private:
void Test (void)
{
cout << "Called B::Test!" << endl;
}

public:
B (void)
{
//=============================================
// Create a function list and add the
// functions we want calling
FunctionList <B>
*function_list = new FunctionList <B>;

function_list->AddFunction (&B::Test);

m_functions.push_back (function_list);
}
};

//=============================================
// A further derived class
//=============================================

class C : public B
{
private:
void Test (void)
{
cout << "Called C::Test!" << endl;
}

public:
C (void)
{
//=============================================
// Create a function list and add the
// functions we want calling
FunctionList <C>
*function_list = new FunctionList <C>;

function_list->AddFunction (&C::Test);

m_functions.push_back (function_list);
}
};

//=============================================
// Program entry point
//=============================================

int main (int argc, char *argv [])
{
A
*test = new C;

test->CallAllFunctions ();

cout << "Done." << endl;

return 0;
}



Skizz

Share this post


Link to post
Share on other sites
Quote:
T *derived = reinterpret_cast <T *> (base);


Using derived in any way except casting it back to base's type has undefined behaviour. In practice, it may work with single inheritance, but will most likely break in presence of multiple or virtual inheritance, because reinterpret_cast will not do the object address adjustments that are necessary to properly handle such cases.

You have been warned.

Share this post


Link to post
Share on other sites
Quote:
Original post by Fruny
Quote:
T *derived = reinterpret_cast <T *> (base);


Using derived in any way except casting it back to base's type has undefined behaviour. In practice, it may work with single inheritance, but will most likely break in presence of multiple or virtual inheritance, because reinterpret_cast will not do the object address adjustments that are necessary to properly handle such cases.

You have been warned.


Yes, I was going to mention that but forgot. You can always use dynamic_cast. You could also store a 'this' pointer with each FunctionList instance and use that instead of passing in an A pointer.

Skizz

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!