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

cool thing with memberfunction pointers as parameters

P: n/a
PKH
This is a technique that was used in an object-oriented program-architecture
in C that I worked with in the past, and I didn't think was possible to do
something similar for classes in C++. Basically it is a way to send virtual
functions as function-parameters, and is useful in cases where you f.ex have
a class that manages other objects and want to call different functions on
these objects without having to rewrite the traversal code for each call.
This may be obvious to many, but I thought it was cool that it could be done
and maybe someone else will find a use for it also.
The drawback is that you need to use a void* to pass any parameters to the
functions.

here is a simple testprogram to show it:
class BaseClass; // foward declaration of class

typedef void (BaseClass::* BaseClassFunc)(void*); // typedef a
functionpointer for

// BaseClass member function.

// The void* is not used here, but

// is meant for any data that would

// need to be passed
class BaseClass
{
protected:
int
m_int;

public:
BaseClass(){m_int = 0;}
virtual void VirtualFunc(void* pxContext) = 0; // just some meaningless
testfunction
void CallVirtual(BaseClassFunc pF, void*
pxContext){(this->*pF)(pxContext);} // call the parameter-function on self
};

class DerivedClass : public BaseClass
{
public:
void VirtualFunc(void* pxContext){m_int = 1;} // override the VirtualFunc
from the BaseClass
};

int main(int argc, char* argv[])
{

DerivedClass
D;

void*
pxContext = NULL;

/* the following actually calls DerivedClass::VirtualFunc on D, as you
can see by stepping into it. */
/* This function would normally be made for some other class, and contain
the traversal-code */
/* but in this example it is just a member of BaseClass */
D.CallVirtual(BaseClass::VirtualFunc, pxContext);

return 0;
}

Jul 22 '05 #1
Share this Question
Share on Google+
2 Replies


P: n/a
"PKH" <no************@online.no> wrote in message news:<c5******************@news2.e.nsc.no>...
class BaseClass; // foward declaration of class

typedef void (BaseClass::* BaseClassFunc)(void*); // typedef a
functionpointer for

// BaseClass member function.

// The void* is not used here, but

// is meant for any data that would

// need to be passed
class BaseClass
{
protected:
int
m_int;

public:
BaseClass(){m_int = 0;}
virtual void VirtualFunc(void* pxContext) = 0; // just some meaningless
testfunction
void CallVirtual(BaseClassFunc pF, void*
pxContext){(this->*pF)(pxContext);} // call the parameter-function on self
};

class DerivedClass : public BaseClass
{
public:
void VirtualFunc(void* pxContext){m_int = 1;} // override the VirtualFunc
from the BaseClass
};

int main(int argc, char* argv[])
{

DerivedClass
D;

void*
pxContext = NULL;

/* the following actually calls DerivedClass::VirtualFunc on D, as you
can see by stepping into it. */
/* This function would normally be made for some other class, and contain
the traversal-code */
/* but in this example it is just a member of BaseClass */
D.CallVirtual(BaseClass::VirtualFunc, pxContext);

return 0;
}


Actually, you must say &BaseClass::VirtualFunc. Your compiler failed
to warn you, so you might want to check if it's warning level is set
too low.

Besides, it's needlessly complex. You can always say
(D.*(&BaseClass::VirtualFunc))(pxContext).

The function CallVirtual does not add any functionality, it only saves
on parentheses.

With boost::bind, you can do even fancier things:

boost::bind( &BaseClass::VirtualFunc, _1, pxContext )( D ).

The boost::bind call creates a unary functor, where the single
argument _1 is substituted on every call. The second parameter
needed for BaseClass::VirtualFunc, pxContext is kept.
The advantage is of course that you can use the same same
context for every call to the created functor. This means
you can pass it to std::for_each, and have for_each provide
the different BaseClass/DerivedClass objects.

Regards,
Michiel Salters
Jul 22 '05 #2

P: n/a
PKH

"Michiel Salters" <Mi*************@logicacmg.com> wrote in message
news:fc*************************@posting.google.co m...
"PKH" <no************@online.no> wrote in message news:<c5******************@news2.e.nsc.no>...
class BaseClass; // foward declaration of class

typedef void (BaseClass::* BaseClassFunc)(void*); // typedef a
functionpointer for

// BaseClass member function.

// The void* is not used here, but

// is meant for any data that would

// need to be passed
class BaseClass
{
protected:
int
m_int;

public:
BaseClass(){m_int = 0;}
virtual void VirtualFunc(void* pxContext) = 0; // just some meaningless testfunction
void CallVirtual(BaseClassFunc pF, void*
pxContext){(this->*pF)(pxContext);} // call the parameter-function on self };

class DerivedClass : public BaseClass
{
public:
void VirtualFunc(void* pxContext){m_int = 1;} // override the VirtualFunc from the BaseClass
};

int main(int argc, char* argv[])
{

DerivedClass
D;

void*
pxContext = NULL;

/* the following actually calls DerivedClass::VirtualFunc on D, as you can see by stepping into it. */
/* This function would normally be made for some other class, and contain the traversal-code */
/* but in this example it is just a member of BaseClass */
D.CallVirtual(BaseClass::VirtualFunc, pxContext);

return 0;
}


Actually, you must say &BaseClass::VirtualFunc. Your compiler failed
to warn you, so you might want to check if it's warning level is set
too low.


I don't think the & is needed. It compiles and runs fine. I've never used &
when taking the address of functions, same as with the address of arrays.

Besides, it's needlessly complex. You can always say
(D.*(&BaseClass::VirtualFunc))(pxContext).

The function CallVirtual does not add any functionality, it only saves
on parentheses.
The point is not to call VirtualFunc directly, but to be able to send a
virtual function as a parameter and have that parameter-function called on
one or more objects. The idea is that you can pass different virtual
functions as the parameter, without rewriting the calling-code. In this
simple example there is no benefit, but if you want to f.ex. traverse some
data-structure and call different virtual functions (passed as the
parameter) on each of the items contained in the data-structure, you would
only need to write the traversal code once.
With boost::bind, you can do even fancier things:

boost::bind( &BaseClass::VirtualFunc, _1, pxContext )( D ).

The boost::bind call creates a unary functor, where the single
argument _1 is substituted on every call. The second parameter
needed for BaseClass::VirtualFunc, pxContext is kept.
The advantage is of course that you can use the same same
context for every call to the created functor. This means
you can pass it to std::for_each, and have for_each provide
the different BaseClass/DerivedClass objects.

Regards,
Michiel Salters


I'm not very familiar with the advanced things you can do with STL, but this
seems to be what I wanted to do (for STL containers).
Pål K Holmberg
Jul 22 '05 #3

This discussion thread is closed

Replies have been disabled for this discussion.