Code Comments
Programming Forum and web based access to our favorite programming groups.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.
Post Follow-up to this messagePraetorian wrote:
> 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
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Post Follow-up to this messageOn Apr 2, 12:05 pm, Praetorian <ashish.anan...@gmail.com> wrote: > 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
Post Follow-up to this messageOn Apr 2, 12:14 pm, "Victor Bazarov" <v.Abaza...@comAcast.net> wrote: > Praetorian wrote: > > > 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
Post Follow-up to this messageIn my example for your second option I wrote:
> 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
Post Follow-up to this messageOn Apr 2, 10:14 am, "Victor Bazarov" <v.Abaza...@comAcast.net> wrote:
> Praetorian wrote:
>
>
>
>
>
>
>
>
>
> 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
> --
> Please remove capital 'A's when replying by e-mail
> I do not respond to top-posted replies, please don't ask
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.
Post Follow-up to this messagePraetorian wrote:
> [..]
> 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
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Post Follow-up to this messageOn Apr 2, 11:25 am, "jason.cipri...@gmail.com" <jason.cipri...@gmail.com> wrote: > On Apr 2, 12:05 pm, Praetorian <ashish.anan...@gmail.com> wrote: > > ... > ... > > 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 apointer to a ClassBfunction, and it can't store apointerto a non-memberfunctioneithe r (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 whatmemberf unctionto 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.
Post Follow-up to this messagePraetorian wrote:
> On Apr 2, 11:25 am, "jason.cipri...@gmail.com"
> <jason.cipri...@gmail.com> wrote:
[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.
--
Jim Langston
tazmaster@rocketmail.com
Post Follow-up to this messageOn Apr 2, 6:05 pm, Praetorian <ashish.anan...@gmail.com> wrote: > 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 =3D (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. -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orient=E9e objet/ Beratung in objektorientierter Datenverarbeitung 9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
Post Follow-up to this messagePowered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.