Member function pointer to member function of another class

P

Praetorian

Hi,
I'm having huge syntax problem dealing with function pointers. Here's
what I'm doing:

I have 2 classes, ClassA and ClassB. ClassA owns an instance of
ClassB. What I want to do is pass a function pointer to a member
function of ClassB as a parameter to a member function of ClassA. I
don't want ClassA's member function to call ClassB's function directly
because ClassA can be used in 2 ways, one of which is a case in which
it does not create an instance of ClassB; hence by passing a function
pointer I can handle that case easily.

This is the code I have:

class ClassB {
public:
BOOL GetFlagX(void) { return m_bFlagX;};
private:
BOOL m_bFlagX;
};

class ClassA {
public:
typedef BOOL (ClassA::*FPAbortFlag)(void);
FPAbortFlag m_fpAbort;

protected:
ClassB *m_pClassB;
BOOL ClassAMemFcn(FPAbortFlag fpAbort);
};

In this case ClassA has new'd an instance of ClassB. What I want to do
is have ClassA's function pointer 'm_fpAbort' point to ClassB's
'GetFlagX' function. Can't seem to figure out the syntax for this.

I did get the following to compile but it wasn't pointing to the
member function associated with ClassA's instance of ClassB:

m_fpAbort = (FPAbortFlag)(&(ClassB::GetFlagX));

How do I do this?

Thanks in advance,
Ashish.
 
V

Victor Bazarov

Praetorian said:
Hi,
I'm having huge syntax problem dealing with function pointers. Here's
what I'm doing:

I have 2 classes, ClassA and ClassB. ClassA owns an instance of
ClassB. What I want to do is pass a function pointer to a member
function of ClassB as a parameter to a member function of ClassA. I
don't want ClassA's member function to call ClassB's function directly
because ClassA can be used in 2 ways, one of which is a case in which
it does not create an instance of ClassB; hence by passing a function
pointer I can handle that case easily.

This is the code I have:

class ClassB {
public:
BOOL GetFlagX(void) { return m_bFlagX;};
private:
BOOL m_bFlagX;
};

class ClassA {
public:
typedef BOOL (ClassA::*FPAbortFlag)(void);
FPAbortFlag m_fpAbort;

protected:
ClassB *m_pClassB;
BOOL ClassAMemFcn(FPAbortFlag fpAbort);
};

In this case ClassA has new'd an instance of ClassB. What I want to do
is have ClassA's function pointer 'm_fpAbort' point to ClassB's
'GetFlagX' function. Can't seem to figure out the syntax for this.

I did get the following to compile but it wasn't pointing to the
member function associated with ClassA's instance of ClassB:

m_fpAbort = (FPAbortFlag)(&(ClassB::GetFlagX));

There should be no need for the cast or for the parentheses.

m_fpAbort = &ClassB::GetFlagX;

If this doesn't work for you, post the code so we can take a closer
look (even copy-and-paste it locally and compile). See FAQ 5.8.

V
 
J

jason.cipriani

I
don't want ClassA's member function to call ClassB's function directly
because ClassA can be used in 2 ways, one of which is a case in which
it does not create an instance of ClassB; hence by passing a function
pointer I can handle that case easily. ....
class ClassA {
public:
typedef BOOL (ClassA::*FPAbortFlag)(void); ....
m_fpAbort = (FPAbortFlag)(&(ClassB::GetFlagX));

You can not do what you are trying to do the way you are trying to do
it. Your code compiles with the explicit cast but will not necessarily
run correctly, and the reason you need an explicit cast to get it to
compile is because the types are not compatible. You have declared
FPAbortFlag as a pointer to a member function in ClassA. That is a
distinctly different type than a pointer to a member function in
ClassB. Your FPAbortFlag can not store pointers to any other functions
besides ones that are members of ClassA -- meaning it can't store a
pointer to a ClassB function, and it can't store a pointer to a non-
member function either (which, if I understand you correctly, is
something you'll eventually want to do if ClassA has no ClassB
instance).

You have a couple of different options. One simple one is:

typedef BOOL (ClassB::*FPAbortFlag) (void);

Note that it is a pointer to a ClassB member. And then, in your ClassA
logic:

if (m_fpAbort && m_pClassB)
m_pClassB->*m_fpAbort();
else
do_the_other_thing();

A second option is to make your ClassB inherit some base class that
describes the interface you are expecting it to have, and change your
definition of ClassA a little to say that it will *always* have an
instance of whatever base class ClassB inherits from (i.e. don't let
it sometimes be used with one, and sometimes be used without one). For
example:

=== BEGIN EXAMPLE ===

class FPAbortHandler {
public:
virtual BOOL FPAbort () = 0;
};

class ClassB : public FPAbortHandler {
public:
BOOL FPAbort () { }
};

class ClassA {
public:
void DoSomething () {
if (m_fpAbort) m_fpAbort->FPAbort();
}
private:
FPAbortHandler *m_fpAbort;
};

=== END EXAMPLE ===

In that case, ClassA could handle anything that implemented the
FPAbortHandler interface, which includes ClassB, or any other object
that you may want to define. This is the way I would personally do it,
because it is a good balance between simplicity and flexibility. If
you need to use the pointer-to-member function to give options of what
member function to call, it can be a:

typedef BOOL (FPAbortHandler::*FPAbortFlag) (void);

And can point to any FPAbortHandler members.

A third option is to make your ClassA a base class for some special
derived classes, leaving the details that are different to the derived
classes. If your ClassA can be used in a few different ways, it is
also appropriate to use two different classes with the common stuff in
ClassA. For example:

=== BEGIN EXAMPLE ===

class ClassA {
...
public:
void DoSomething () {
...
DoIt();
...
}
protected:
virtual void DoIt () = 0;
...
};

class ClassAWithB : public ClassA {
...
private:
typedef BOOL (ClassB::*FPAbortFlag)(void);
ClassB *m_pClassB;
FPAbortFlag *m_fpAbort;
protected:
void DoIt () { m_pClassB->*m_fpAbort(); }
...
};

class ClassAWithOtherFunction : public ClassA {
...
private:
...
protected:
void DoIt () { ... }
...
};

=== END EXAMPLE ===

In that case, DoIt() takes care of all the differences.
ClassA::DoSomething() does a bunch of stuff and calls DoIt() for
derived-class-specific details. The DoIt() function does the right
thing. Sorry I'm being vague, but it's a general issue.

Using inheritance allows you to access everything via ClassA pointers,
as well:

ClassA *things[2];
things[0] = new ClassAWithB(MyClassB); // or whatever
things[1] = new ClassAWithOtherFunction(...);

Or, of course:

void function (ClassA *a) {
a->DoSomething();
}

And you can pass anything to that function(), and the right thing will
always happen.


Hope that helps, or at least is coherent,
Jason
 
J

jason.cipriani

There should be no need for the cast or for the parentheses.

m_fpAbort = &ClassB::GetFlagX;


The problem is that his FPAbortFlag is actually:

typedef BOOL (ClassA::*FPAbortFlag)(void);

Pointer to ClassA member, not ClassB.

Jason
 
J

jason.cipriani

In said:
class ClassA {
public:
void DoSomething () {
if (m_fpAbort) m_fpAbort->FPAbort();
}

But to be consistent with what I described, remove the "if
(m_fpAbort)":

public:
void DoSomething () {
assert(m_fpAbort != NULL);
m_fpAbort->FPAbort();
}

It doesn't matter one way or the other, whichever is more appropriate;
but I *did* describe "changing the rules" for a ClassA, so I should
stick to them for consistency.

Jason
 
P

Praetorian

There should be no need for the cast or for the parentheses.

m_fpAbort = &ClassB::GetFlagX;

If this doesn't work for you, post the code so we can take a closer
look (even copy-and-paste it locally and compile). See FAQ 5.8.

V

Victor,
That didn't work; I get the following compiler error:

error C2440: '=' : cannot convert from 'BOOL (__thiscall
CBootLoaderDlg::* )(void)' to 'CFlashDownload::FPFlashAbort'
Types pointed to are unrelated; conversion requires
reinterpret_cast, C-style cast or function-style cast

I tried the reinterpret_cast suggestion as follows:

m_fpAbortFlash = reinterpret_cast <FPFlashAbort>
&CBootLoaderDlg::GetDlgCancelledFlag;

That compiles but the function never returns true; even though I can
breakpoint and verify that the flag is set. It looks like it isn't
pointing to the correct instance of CBootLoaderDlg.

Here are snippets of the actual code:

In FlashDownload.h

#include "BootLoader.h"
#include "BootLoaderDlg.h"

class CFlashDownload
{
public:
/* Constructor/Destructor */
CFlashDownload();
~CFlashDownload();

void FlashDownloadWithUI(void);
private:
CBootLoaderDlg *m_pBootDlg;

typedef BOOL (CFlashDownload::*FPFlashAbort)();
FPFlashAbort m_fpAbortFlash;

BOOL Flash2812InternalRam(FPFlashAbort fpAbortFlash);
};

In BootloaderDlg.h

class CBootLoaderDlg : public CDialog
{
DECLARE_DYNAMIC(CBootLoaderDlg)

public:
BOOL GetDlgCancelledFlag(void) { return m_bDlgCancelled; };
private:
BOOL m_bDlgCancelled;
};

In FlashDownload.cpp

void CFlashDownload::FlashDownloadWithUI(void)
{
if( m_pBootDlg != NULL ) {
AfxMessageBox( _T("Recursive call to FlashDownloadWithUI()
detected") );
AfxThrowUserException();
}

m_pBootDlg = new CBootLoaderDlg();
m_pBootDlg->Create( IDD_MAIN_DLG, AfxGetMainWnd() );

m_fpAbortFlash = &CBootLoaderDlg::GetDlgCancelledFlag;
/* Call flash download function */
Flash2812InternalRam(m_fpAbortFlash);

m_pBootDlg->DestroyWindow();
delete m_pBootDlg;
}

CBootLoaderDlg sets m_bDlgCancelled when the dialog is cancelled
(within its OnCancel()) method).

Thanks for your help, I really appreciate it. Sorry for this silly
question but you mentioned I should look at section 5.8 of the C++ FAQ
but how do I get to the FAQ?

Ashish.
 
V

Victor Bazarov

Praetorian said:
[..]
Here are snippets of the actual code:

In FlashDownload.h

#include "BootLoader.h"
#include "BootLoaderDlg.h"

class CFlashDownload
{
public:
/* Constructor/Destructor */
CFlashDownload();
~CFlashDownload();

void FlashDownloadWithUI(void);

Drop the second 'void'. Make it look different from the constructor
and the destructor, which isn't true -- all of them do NOT take any
arguments.
private:
CBootLoaderDlg *m_pBootDlg;

typedef BOOL (CFlashDownload::*FPFlashAbort)();
FPFlashAbort m_fpAbortFlash;

Why is 'm_fpAbortFlash' is a member of CFlashDownload? If you
intend to call it with 'm_pBootDlg' that is of type 'CBootLoaderDlg',
then it would seem logical to make 'FPFlashAbort' to be a typedef
for "a pointer to member of 'CBootLoaderDlg'", no?
BOOL Flash2812InternalRam(FPFlashAbort fpAbortFlash);
};

In BootloaderDlg.h

class CBootLoaderDlg : public CDialog
{
DECLARE_DYNAMIC(CBootLoaderDlg)

public:
BOOL GetDlgCancelledFlag(void) { return m_bDlgCancelled; };

Drop the 'void' please.
private:
BOOL m_bDlgCancelled;
};

In FlashDownload.cpp

void CFlashDownload::FlashDownloadWithUI(void)

Drop the 'void'.
{
if( m_pBootDlg != NULL ) {
AfxMessageBox( _T("Recursive call to FlashDownloadWithUI()
detected") );
AfxThrowUserException();
}

m_pBootDlg = new CBootLoaderDlg();
m_pBootDlg->Create( IDD_MAIN_DLG, AfxGetMainWnd() );

m_fpAbortFlash = &CBootLoaderDlg::GetDlgCancelledFlag;
/* Call flash download function */
Flash2812InternalRam(m_fpAbortFlash);

m_pBootDlg->DestroyWindow();
delete m_pBootDlg;
}

CBootLoaderDlg sets m_bDlgCancelled when the dialog is cancelled
(within its OnCancel()) method).
OK...

Thanks for your help, I really appreciate it. Sorry for this silly
question but you mentioned I should look at section 5.8 of the C++ FAQ
but how do I get to the FAQ?

How long have you been reading this newsgroup?

http://www.parashift.com/c++-faq-lite/

V
 
P

Praetorian

I
don't want ClassA'smemberfunctionto call ClassB'sfunctiondirectly
because ClassA can be used in 2 ways, one of which is a case in which
it does not create an instance of ClassB; hence by passing afunction
pointerI can handle that case easily. ...
classClassA {
public:
typedef BOOL (ClassA::*FPAbortFlag)(void); ...
m_fpAbort = (FPAbortFlag)(&(ClassB::GetFlagX));

You can not do what you are trying to do the way you are trying to do
it. Your code compiles with the explicit cast but will not necessarily
run correctly, and the reason you need an explicit cast to get it to
compile is because the types are not compatible. You have declared
FPAbortFlag as apointerto amemberfunctionin ClassA. That is a
distinctly different type than apointerto amemberfunctionin
ClassB. Your FPAbortFlag can not store pointers to any other functions
besides ones that are members of ClassA -- meaning it can't store apointerto a ClassBfunction, and it can't store apointerto a non-memberfunctioneither (which, if I understand you correctly, is
something you'll eventually want to do if ClassA has no ClassB
instance).

You have a couple of different options. One simple one is:

typedef BOOL (ClassB::*FPAbortFlag) (void);

Note that it is apointerto a ClassBmember. And then, in your ClassA
logic:

if (m_fpAbort && m_pClassB)
m_pClassB->*m_fpAbort();
else
do_the_other_thing();

A second option is to make your ClassB inherit some baseclassthat
describes the interface you are expecting it to have, and change your
definition of ClassA a little to say that it will *always* have an
instance of whatever baseclassClassB inherits from (i.e. don't let
it sometimes be used with one, and sometimes be used without one). For
example:

=== BEGIN EXAMPLE ===

classFPAbortHandler {
public:
virtual BOOL FPAbort () = 0;

};

classClassB : public FPAbortHandler {
public:
BOOL FPAbort () { }

};

classClassA {
public:
void DoSomething () {
if (m_fpAbort) m_fpAbort->FPAbort();
}
private:
FPAbortHandler *m_fpAbort;

};

=== END EXAMPLE ===

In that case, ClassA could handle anything that implemented the
FPAbortHandler interface, which includes ClassB, or any other object
that you may want to define. This is the way I would personally do it,
because it is a good balance between simplicity and flexibility. If
you need to use thepointer-to-memberfunctionto give options of whatmemberfunctionto call, it can be a:

typedef BOOL (FPAbortHandler::*FPAbortFlag) (void);

And can point to any FPAbortHandler members.

A third option is to make your ClassA a baseclassfor some special
derived classes, leaving the details that are different to the derived
classes. If your ClassA can be used in a few different ways, it is
also appropriate to use two different classes with the common stuff in
ClassA. For example:

=== BEGIN EXAMPLE ===

classClassA {
...
public:
void DoSomething () {
...
DoIt();
...
}
protected:
virtual void DoIt () = 0;
...
};

classClassAWithB : public ClassA {
...
private:
typedef BOOL (ClassB::*FPAbortFlag)(void);
ClassB *m_pClassB;
FPAbortFlag *m_fpAbort;
protected:
void DoIt () { m_pClassB->*m_fpAbort(); }
...
};

classClassAWithOtherFunction : public ClassA {
...
private:
...
protected:
void DoIt () { ... }
...
};

=== END EXAMPLE ===

In that case, DoIt() takes care of all the differences.
ClassA::DoSomething() does a bunch of stuff and calls DoIt() for
derived-class-specific details. The DoIt()functiondoes the right
thing. Sorry I'm being vague, but it's a general issue.

Using inheritance allows you to access everything via ClassA pointers,
as well:

ClassA *things[2];
things[0] = new ClassAWithB(MyClassB); // or whatever
things[1] = new ClassAWithOtherFunction(...);

Or, of course:

voidfunction(ClassA *a) {
a->DoSomething();

}

And you can pass anything to thatfunction(), and the right thing will
always happen.

Hope that helps, or at least is coherent,
Jason

Jason,
I like the solution of creating another class that both the other
classes inherit from and have it handle the function pointers. The
problem with that implementation in my case is that both the classes I
described are in a DLL; the DLL has 2 interfaces, one which causes
ClassA to create an instance of ClassB or a second interface where the
ClassA member function in question must be able to accept a function
pointer (which may be to a member function of an arbitrary class). In
that case, it wouldn't be possible to have the user of the DLL
inheriting from a class which is hidden with the DLL itself. Maybe my
approach to this problem is incorrect; I'm not a C programmer, not
very good with C++, so there probably is a better way to do this. What
I ideally want is a C-like way of passing around function pointers
that can be called by anyone.

Ashish.
 
J

Jim Langston

Praetorian said:
You can not do what you are trying to do the way you are trying to do
it. Your code compiles with the explicit cast but will not
necessarily ...
[SNIP]

Jason,
I like the solution of creating another class that both the other
classes inherit from and have it handle the function pointers. The
problem with that implementation in my case is that both the classes I
described are in a DLL; the DLL has 2 interfaces, one which causes
ClassA to create an instance of ClassB or a second interface where the
ClassA member function in question must be able to accept a function
pointer (which may be to a member function of an arbitrary class). In
that case, it wouldn't be possible to have the user of the DLL
inheriting from a class which is hidden with the DLL itself. Maybe my
approach to this problem is incorrect; I'm not a C programmer, not
very good with C++, so there probably is a better way to do this. What
I ideally want is a C-like way of passing around function pointers
that can be called by anyone.

There is a problem with that. A class function has a hidden first parameter
called this which is a pointer to the instance of the class.

I.E.

class Foo
{
void MyFunc( int i );
};

MyFunc has a hidden first parameter this which would look like this if it
was spelled out:
void MyFunc( Foo* this, int i );

When you declare a class function pointer the compiler knows about the
hidden this pointer.

Now the problems.

You can not mix pointers between classes as you are trying to do because the
compiler has to know what parameters the function accepts. Is the first
parameter ClassA*, ClassB or no hidden first parameter (stand alone
function).

You might be able to get away with some form of void* as the first
parameter, but I doubt it. Also, what about stand alone functions that
don't have a hidden first parameter?

You might just want to go with stand alone function pointers and accept a
void* to the instance if required, although if this is a call back function
how is your calling function going to know what to place?

I think you might want to rethink your program design.
 
J

James Kanze

I'm having huge syntax problem dealing with function pointers.
Here's what I'm doing:
I have 2 classes, ClassA and ClassB. ClassA owns an instance
of ClassB. What I want to do is pass a function pointer to a
member function of ClassB as a parameter to a member function
of ClassA. I don't want ClassA's member function to call
ClassB's function directly because ClassA can be used in 2
ways, one of which is a case in which it does not create an
instance of ClassB; hence by passing a function pointer I can
handle that case easily.
This is the code I have:
class ClassB {
public:
BOOL GetFlagX(void) { return m_bFlagX;};
private:
BOOL m_bFlagX;
};
class ClassA {
public:
typedef BOOL (ClassA::*FPAbortFlag)(void);
FPAbortFlag m_fpAbort;
protected:
ClassB *m_pClassB;
BOOL ClassAMemFcn(FPAbortFlag fpAbort);
};
In this case ClassA has new'd an instance of ClassB. What I
want to do is have ClassA's function pointer 'm_fpAbort' point
to ClassB's 'GetFlagX' function. Can't seem to figure out the
syntax for this.
I did get the following to compile but it wasn't pointing to
the member function associated with ClassA's instance of
ClassB:
m_fpAbort = (FPAbortFlag)(&(ClassB::GetFlagX));

Could you please explain what you mean by that last sentence?
&(ClassB::GetFlagX) definitely points to a member function of
ClassB. The conversion doesn't change that. (Of course, the
only thing you can legally do with the converted pointer is cast
it back to the original type, and invoke it through a pointer to
ClassB.) And pointers to members aren't associated with any
instance, so saying that it should point to a specific instance
doesn't make sense.

If what you want is to pass someone who only knows about ClassA
a pointer to a ClassA and a pointer to member of ClassA, then
all that someone can do is invoke a function of ClassA. If you
want it to invoke a function on the ClassB instance owned by the
ClassA instance you passed it, you'll have to create a
forwarding function in ClassA, and pass a pointer to member to
it. Most of the time, however, it is better to provide some
sort of functional object, and handle all of the indirections
there, rather than to confuse the issue with pointers to member
functions and such.
 
P

Praetorian

Could you please explain what you mean by that last sentence?
&(ClassB::GetFlagX) definitely points to a member function of
ClassB. The conversion doesn't change that. (Of course, the
only thing you can legally do with the converted pointer is cast
it back to the original type, and invoke it through a pointer to
ClassB.) And pointers to members aren't associated with any
instance, so saying that it should point to a specific instance
doesn't make sense.

If what you want is to pass someone who only knows about ClassA
a pointer to a ClassA and a pointer to member of ClassA, then
all that someone can do is invoke a function of ClassA. If you
want it to invoke a function on the ClassB instance owned by the
ClassA instance you passed it, you'll have to create a
forwarding function in ClassA, and pass a pointer to member to
it. Most of the time, however, it is better to provide some
sort of functional object, and handle all of the indirections
there, rather than to confuse the issue with pointers to member
functions and such.

--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

James,
Thanks for your reply. I figured out the problem with my original
posting. The function pointer needed to be a member of ClassB since it
was pointing to a ClassB member function. What I really want to do is
to be able to accept any arbitrary function pointer that has been
passed to a ClassA member function and call the function pointed to by
the pointer. Both ClassA and ClassB are part of a DLL and so I'll have
no prior knowledge of the type of function pointer being passed to me.
It could be a pointer to some other class' member function or to a
standalone function. This is easy to do in C because function pointers
do not belong to a class in that case. Your suggestion about providing
a functional object to handle indirection is interesting; sounds like
that's what I need. Could you please elaborate on this further or
point me to where I can find more information on this? I really
appreciate your help.

Ashish.
 
J

James Kanze

On Apr 3, 2:38 am, James Kanze <[email protected]> wrote:

[...]
Your suggestion about providing
a functional object to handle indirection is interesting; sounds like
that's what I need. Could you please elaborate on this further or
point me to where I can find more information on this? I really
appreciate your help.

I'm not sure if it's ever really been documented as a pattern;
it was widespread before patterns became widely known.
Basically, your class defines an abstract base class:

class AbstractCallback
{
public:
virtual AbstractCallback() {}
virtual void operator()() const = 0 ;
} ;

and the function the client calls looks something like:

void registerCallback( AbstractCallback const& cb ) ;

The client then derives from AbstractCallback, and passes an
instance of the derived class.

For convenience, you could even provide a template for the
concrete class:

template< typename T, void (T::*fnc)() >
class Callback : public AbstractCallback
{
public:
explicit Callback( T* object )
: myObj( object )
{
}

virtual void operator()() const
{
(myObj->*fnc)() ;
}

private:
T* myObj ;
} ;

The user then creates an instance of Callback< MyClass,
&MyClass::whatever >( this ), and passes you it. (Long before
templates, we used a macro for the derived class.)

Alternatively, your function could be a template, taking a
functional object. But I rather think you'd have problems
bundling that into a DLL.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,967
Messages
2,570,148
Members
46,694
Latest member
LetaCadwal

Latest Threads

Top