By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,454 Members | 3,103 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,454 IT Pros & Developers. It's quick & easy.

The callback-to-derived-member function problem

P: n/a
Hi all

I have a class (cPort) that is designed to receive objects and,
depending on the type, call a handler (callback) in any descendant of a
cProcessBlock class. Callback functions take a shared_ptr<cBaseas a
parameter, and return void.

The code was working fine, although I have encountered problems (under
a Microsoft compiler, of course - VC 8.0) when I attempt to add
callbacks to a class with multiple inheritance. I hate multiple
inheritance in general, but this is necessary to interface with another
library. I think there is some issue regarding the size of member
function pointers in VC.

Anyway - I believe that this code can be converted to use
boost::function and/or boost::bind to iron out these issues. The
problem is that I am going more than slightly squint when I read the
boost docs.

I have attached a reduced set of my code below. I would be extremely
grateful if someone could point out how this code could be converted to
use the boost representations.

Thanks for any and all replies!

Ryan

typedef void (cProcessBlock::*PortCallbackFnPtr)(shared_ptr<cBa se>);

// structure that associates a callback function pointer with the
required caller
class cPortCallback : public cBase
{
public:
cPortCallback() :
m_pPortCallbackFn(NULL), m_pCaller(m_pNULL) { }
cPortCallback(PortCallbackFnPtr pPortCallbackFn,
shared_ptr<cBasepCaller) :
m_pPortCallbackFn(pPortCallbackFn), m_pCaller(pCaller) { }
PortCallbackFnPtr m_pPortCallbackFn;
shared_ptr<cBasem_pCaller;
};

class cPort : public cProcessBlock
{
public:
/// Add a new callback
void AddCallback(PortCallbackFnPtr NewCallbackFnPtr, std::string
strClassName,
shared_ptr<cBasepCaller);

protected:
/// Callback registry (map of callback handlers)
map<string, cPortCallbackm_CallbackRegistry;
};

void cPort::AddCallback(PortCallbackFnPtr NewCallbackFnPtr, std::string
strClassName,
shared_ptr<cBasepCaller)
{
m_CallbackRegistry[strClassName] = cPortCallback(NewCallbackFnPtr,
pCaller);
}

bool cPort::Timeslice()
// (called repeatedly in thread) - continuously receive new objects and
process using callbacks
{
shared_ptr<cBasepNewObject;
pNewObject = Receive();

// Call appropriate callback depending on the received object's
class name
if (pNewObject) {
PortCallbackFnPtr CallbackFn =
m_CallbackRegistry[pNewObject->ClassName()].m_pPortCallbackFn;
if (CallbackFn) // if appropriate callback handler is found

((*(shared_polymorphic_cast<cProcessBlock>(m_Callb ackRegistry[pNewObject->ClassName()].m_pCaller))).*(CallbackFn))(pNewObject);
}
return true;
}
An example of adding a callback:
AddCallback(static_cast<PortCallbackFnPtr>(&cGraph ::OnNewGraphData),
"cRealMatrix", this);

Aug 25 '06 #1
Share this Question
Share on Google+
3 Replies


P: n/a
ry***********@gmail.com wrote:
Hi all

I have a class (cPort) that is designed to receive objects and,
depending on the type, call a handler (callback) in any descendant of a
cProcessBlock class. Callback functions take a shared_ptr<cBaseas a
parameter, and return void.

The code was working fine, although I have encountered problems (under
a Microsoft compiler, of course - VC 8.0) when I attempt to add
callbacks to a class with multiple inheritance. I hate multiple
inheritance in general, but this is necessary to interface with another
library. I think there is some issue regarding the size of member
function pointers in VC.

Anyway - I believe that this code can be converted to use
boost::function and/or boost::bind to iron out these issues. The
problem is that I am going more than slightly squint when I read the
boost docs.

I have attached a reduced set of my code below. I would be extremely
grateful if someone could point out how this code could be converted to
use the boost representations.

Thanks for any and all replies!

Ryan

typedef void (cProcessBlock::*PortCallbackFnPtr)(shared_ptr<cBa se>);

// structure that associates a callback function pointer with the
required caller
class cPortCallback : public cBase
{
public:
cPortCallback() :
m_pPortCallbackFn(NULL), m_pCaller(m_pNULL) { }
cPortCallback(PortCallbackFnPtr pPortCallbackFn,
shared_ptr<cBasepCaller) :
m_pPortCallbackFn(pPortCallbackFn), m_pCaller(pCaller) { }
PortCallbackFnPtr m_pPortCallbackFn;
shared_ptr<cBasem_pCaller;
};

class cPort : public cProcessBlock
{
public:
/// Add a new callback
void AddCallback(PortCallbackFnPtr NewCallbackFnPtr, std::string
strClassName,
shared_ptr<cBasepCaller);

protected:
/// Callback registry (map of callback handlers)
map<string, cPortCallbackm_CallbackRegistry;
};

void cPort::AddCallback(PortCallbackFnPtr NewCallbackFnPtr, std::string
strClassName,
shared_ptr<cBasepCaller)
{
m_CallbackRegistry[strClassName] = cPortCallback(NewCallbackFnPtr,
pCaller);
}

bool cPort::Timeslice()
// (called repeatedly in thread) - continuously receive new objects and
process using callbacks
{
shared_ptr<cBasepNewObject;
pNewObject = Receive();

// Call appropriate callback depending on the received object's
class name
if (pNewObject) {
PortCallbackFnPtr CallbackFn =
m_CallbackRegistry[pNewObject->ClassName()].m_pPortCallbackFn;
if (CallbackFn) // if appropriate callback handler is found

((*(shared_polymorphic_cast<cProcessBlock>(m_Callb ackRegistry[pNewObject->ClassName()].m_pCaller))).*(CallbackFn))(pNewObject);
}
return true;
}
An example of adding a callback:
AddCallback(static_cast<PortCallbackFnPtr>(&cGraph ::OnNewGraphData),
"cRealMatrix", this);
You might want to ask on the Boost user's list, but since the
components you're talking about are mostly in TR1 (not counting
shared_polymorphic_cast), if you post a more complete example that
demonstrates the problem and that we can cut and paste into our editors
unchanged (see the guidelines for posting code:
http://parashift.com/c++-faq-lite/ho....html#faq-5.8), we can
probably help you here.

Cheers! --M

Aug 25 '06 #2

P: n/a
Using boost::bind and boost::function for member function call backs is
actually surprisingly easy. You just make sure the first parameter you
bind is the 'this' object you want to call the member function on.

boost::function<void (void)f;
f = boost::bind(&MyClass::MyMethod, this);

If you have additional parameters left that should be called on f:

boost::function<void (int, int)f;
f = boost::bind(&MyClass::MyMethod, this, _1, _2);

This says, "MyMethod is a member function that takes two ints and
returns void. For the first parameter always give it 'this.'" which
effectively makes f a function that now takes 2 variables instead of 3
(before it took the 'this' pointer and two additional parameters). If
you did:

f = boost::bind(&MyClass::MyMethod, this, _1, _1);

Now f will take only 1 parameter, and it will pass it as both the first
and second parameter to MyMethod.

I usually just make the particular boost::function<template needed a
typedef.

mlimber wrote:
ry***********@gmail.com wrote:
Hi all

I have a class (cPort) that is designed to receive objects and,
depending on the type, call a handler (callback) in any descendant of a
cProcessBlock class. Callback functions take a shared_ptr<cBaseas a
parameter, and return void.

The code was working fine, although I have encountered problems (under
a Microsoft compiler, of course - VC 8.0) when I attempt to add
callbacks to a class with multiple inheritance. I hate multiple
inheritance in general, but this is necessary to interface with another
library. I think there is some issue regarding the size of member
function pointers in VC.

Anyway - I believe that this code can be converted to use
boost::function and/or boost::bind to iron out these issues. The
problem is that I am going more than slightly squint when I read the
boost docs.

I have attached a reduced set of my code below. I would be extremely
grateful if someone could point out how this code could be converted to
use the boost representations.

Thanks for any and all replies!

Ryan

typedef void (cProcessBlock::*PortCallbackFnPtr)(shared_ptr<cBa se>);

// structure that associates a callback function pointer with the
required caller
class cPortCallback : public cBase
{
public:
cPortCallback() :
m_pPortCallbackFn(NULL), m_pCaller(m_pNULL) { }
cPortCallback(PortCallbackFnPtr pPortCallbackFn,
shared_ptr<cBasepCaller) :
m_pPortCallbackFn(pPortCallbackFn), m_pCaller(pCaller) { }
PortCallbackFnPtr m_pPortCallbackFn;
shared_ptr<cBasem_pCaller;
};

class cPort : public cProcessBlock
{
public:
/// Add a new callback
void AddCallback(PortCallbackFnPtr NewCallbackFnPtr, std::string
strClassName,
shared_ptr<cBasepCaller);

protected:
/// Callback registry (map of callback handlers)
map<string, cPortCallbackm_CallbackRegistry;
};

void cPort::AddCallback(PortCallbackFnPtr NewCallbackFnPtr, std::string
strClassName,
shared_ptr<cBasepCaller)
{
m_CallbackRegistry[strClassName] = cPortCallback(NewCallbackFnPtr,
pCaller);
}

bool cPort::Timeslice()
// (called repeatedly in thread) - continuously receive new objects and
process using callbacks
{
shared_ptr<cBasepNewObject;
pNewObject = Receive();

// Call appropriate callback depending on the received object's
class name
if (pNewObject) {
PortCallbackFnPtr CallbackFn =
m_CallbackRegistry[pNewObject->ClassName()].m_pPortCallbackFn;
if (CallbackFn) // if appropriate callback handler is found

((*(shared_polymorphic_cast<cProcessBlock>(m_Callb ackRegistry[pNewObject->ClassName()].m_pCaller))).*(CallbackFn))(pNewObject);
}
return true;
}
An example of adding a callback:
AddCallback(static_cast<PortCallbackFnPtr>(&cGraph ::OnNewGraphData),
"cRealMatrix", this);

You might want to ask on the Boost user's list, but since the
components you're talking about are mostly in TR1 (not counting
shared_polymorphic_cast), if you post a more complete example that
demonstrates the problem and that we can cut and paste into our editors
unchanged (see the guidelines for posting code:
http://parashift.com/c++-faq-lite/ho....html#faq-5.8), we can
probably help you here.

Cheers! --M
Aug 25 '06 #3

P: n/a

k0*****@gmail.com wrote:
Using boost::bind and boost::function for member function call backs is
actually surprisingly easy. You just make sure the first parameter you
bind is the 'this' object you want to call the member function on.
Thanks! The conversion did indeed turn out to be surprisingly more easy
than I was expecting . . .

I hope the performance penalty of the "bind" stuff is not too high, but
I think the clarity of the code is probably worth it.

Ryan

Aug 28 '06 #4

This discussion thread is closed

Replies have been disabled for this discussion.