Pointer-to-member-function pointing to a member function of an inherited class

A

akiriwas

The subject basically says what I am having trouble with. For an
example lets say I have a class A which has a function f. I then also
have a class B which inherits from A and has a function g.

class A
{
public: void f(int,float);
};

class B : public A
{
public: void g(int, float);
};


Okay, now with all that setup, if I created a pointer to a member
function something like this:

typedef void (A::*MFP)(int a, float b);

if I then use it such as

MFP mfp = &A::f;

then everything works fine.

even if I do:

MFP mfp2 = &B::f;

then everything still works (presumably because f is not defined in B
and must then be from A). However, if I try this:

MFP mfp3 = &B::g;

then it complains that B::g is not of the right type since it is not a
member function of class A. The protype signature is the same, both
(int, float), is there no way to make this work? It seemed to me that
it should have worked since any instance of B is still by definition an
instance of A. Anyone done anything like this?

-akiriwas
 
G

Gianni Mariani

The subject basically says what I am having trouble with. For an
example lets say I have a class A which has a function f. I then also
have a class B which inherits from A and has a function g.

class A
{
public: void f(int,float);
};

class B : public A
{
public: void g(int, float);
};


Okay, now with all that setup, if I created a pointer to a member
function something like this:

typedef void (A::*MFP)(int a, float b);

Try making this :

typedef void (B::*MFP)(int a, float b);
if I then use it such as

MFP mfp = &A::f;

then everything works fine.

even if I do:

MFP mfp2 = &B::f;

&B::f becomes &A::f when the compiler is done with it because f is a
member of A - this is some magic specified by the standard and only
works with literal pointer to members.

An A::* member pointer can be converted to a B::* member pointer but not
the other way. i.e.

typedef void (A::*AMFP)(int a, float b);
typedef void (B::*BMFP)(int a, float b);
void f( AMFP a, AMFP b )
{
b = a; // legal
a = b; // illegal
}
then everything still works (presumably because f is not defined in B
and must then be from A). However, if I try this:

MFP mfp3 = &B::g;

Think about it - an object of type A can't really support a method of
class B since it's impossible to really which type of object you really
have.
then it complains that B::g is not of the right type since it is not a
member function of class A. The protype signature is the same, both
(int, float), is there no way to make this work? It seemed to me that
it should have worked since any instance of B is still by definition an
instance of A. Anyone done anything like this?

Yes.

options for this case are:

a) use virtual methods
b) use functions (not member functions)
 
M

Mike Wahler

The subject basically says what I am having trouble with. For an
example lets say I have a class A which has a function f. I then also
have a class B which inherits from A and has a function g.

class A
{
public: void f(int,float);
};

class B : public A
{
public: void g(int, float);
};


Okay, now with all that setup, if I created a pointer to a member
function something like this:

typedef void (A::*MFP)(int a, float b);

if I then use it such as

MFP mfp = &A::f;

then everything works fine.

even if I do:

MFP mfp2 = &B::f;

then everything still works (presumably because f is not defined in B
and must then be from A). However, if I try this:

MFP mfp3 = &B::g;

then it complains that B::g is not of the right type since it is not a
member function of class A.
Correct.

The protype signature is the same,

Same as what? You seem to think that a 'B' object has
more than one function named 'g'. There is only one,
the member of 'A' (which is a member of 'B') .
both
(int, float), is there no way to make this work? It seemed to me that
it should have worked since any instance of B is still by definition an
instance of A.

But 'g' is still only a member of 'A', it's not a member of 'B'.
When you derive 'B' from 'A', 'A' is *contained* by 'B'. There
is no 'duplication' of members. A 'B' object will have two
'parts': the 'A' part, and the 'part' containing any members
defined only in 'B' (if any).

What are you trying to do that you think you can't using
&A::g ??
Anyone done anything like this?

No, because there's no need. What specifically are you
trying to do?

-Mike
 
M

Matthew Schaefer

Look at this way with different names:
1) a Person has a name
2) a Student has a name
3) but not every Person has a grade.

class Person
{
public:
void name(int,float);
};


class Student : public Person
{
public:
void grade(int, float);
};

int main() {

typedef void (Person::*MFP)(int a, float b);

MFP mfp1 = &Person::name;
MFP mfp2 = &Student::name;
MFP mfp3 = &Student::grade;
return 0;
}
 
S

Shezan Baig

The subject basically says what I am having trouble with. For an
example lets say I have a class A which has a function f. I then also
have a class B which inherits from A and has a function g.

class A
{
public: void f(int,float);
};

class B : public A
{
public: void g(int, float);
};


Okay, now with all that setup, if I created a pointer to a member
function something like this:

typedef void (A::*MFP)(int a, float b);


This means you can call an MFP function with an object of type A.

if I then use it such as

MFP mfp = &A::f;

then everything works fine.

even if I do:

MFP mfp2 = &B::f;

then everything still works (presumably because f is not defined in B

Yes, because you can call f(...) using an object of type A. A and B
are of type A.

and must then be from A). However, if I try this:

MFP mfp3 = &B::g;

then it complains that B::g is not of the right type since it is not a
member function of class A.

This will not work, because you cannot call g(...) using all objects of
type A. A pointer to 'A' is not necessarily an object of type B, so if
I have class C, which also derives from A, I must not be able to call
g(...) using an object of type C.

-shez-
 
A

akiriwas

Basically, I have a base class, I want to be able to be able to have
keep a list of pointers to member functions such that they all have the
same type. For instance somefunction(int, float). But I also want
someone else to be able to subclass the baseclass, create their own
member function with the same type, for instance someotherfunction(int,
float) and have the function pointer still be able to point to it.
-akiriwas
 
A

akiriwas

This is exactly what I'm trying to do in the case you have with MFP
mfp3 = &Student::grade. However, when I compile the exact code you
show with g++ it gives me the error

error: cannot convert `void (Student::*)(int, float)' to `void
(Person::*)(int, float)' in initialization
Did the code you wrote work for you?

-akiriwas
 
S

Shezan Baig

Basically, I have a base class, I want to be able to be able to have
keep a list of pointers to member functions such that they all have the
same type. For instance somefunction(int, float). But I also want
someone else to be able to subclass the baseclass, create their own
member function with the same type, for instance someotherfunction(int,
float) and have the function pointer still be able to point to it.
-akiriwas

This is simply not possible.

class A { ... };
class B : public A { ... };
class C : public A { ... };

A a;
B b;
C c;

If I have a function pointer to a method in class A, I am guaranteed to
be able to call that function using any object derived from A (that
means I can use it with 'a', 'b', and 'c').

It *cannot* point to a method in class B. What would happen if I call
the function using 'c'??

Pls let us know why you are trying to do this. There is probably a
much better, more elegant, solution instead of using function pointers.
-shez-
 
S

Shezan Baig

Shezan said:
class A { ... };
class B : public A { ... };
class C : public A { ... };

A a;
B b;
C c;

If I have a function pointer to a method in class A, I am guaranteed to
be able to call that function using any object derived from A (that
means I can use it with 'a', 'b', and 'c').

It *cannot* point to a method in class B. What would happen if I call
the function using 'c'??


Or even 'a'??
 
M

Matthew Schaefer

No, it does not work. I was trying to demonstrate intuitively that it's
incorrect.
 
A

akiriwas

Okay.. I get it now. Well, you definitely hit the nail on the head for
what I was trying to do, but obviously now cannot. Are there any
suggestions on what I can do to do something like it? By the way,
thanks for the help so far.

-akiriwas
 
S

Shezan Baig

Okay.. I get it now. Well, you definitely hit the nail on the head for
what I was trying to do, but obviously now cannot. Are there any
suggestions on what I can do to do something like it? By the way,
thanks for the help so far.

-akiriwas

You probably want to use virtual functions. For example:

class A {
public:
virtual void mfp(int a, double b)
{
doSomething(...);
}
};

class B : public A {
public:
virtual void mfp(int a, double b) // overriding A::mfp(...)
{
doSomethingElse(...);
}
};

A a;
B b;

A *pA1 = &a;
A *pA2 = &b;

pA1->mfp(...); // will call A::mfp(...)
pA2->mfp(...); // will call B::mfp(...)

Hope this helps,
-shez-
 
F

fluden

All the other fellows said I agree, but you
can also do exactly what you want by doing:

MFP mfp3 = (MFP) &B::g;

Took me forever to get this right, but it is
a very useful technique. I have a simple
base class A with nothing. Then I have lots of
different methods that do various different things on many different
classes B, C that are derived
from A. If I add stuff to class B and allow the
proper pointers to be set, I don't want to
go back to A and add one more virtual class.
Besides C also inherited from A might have
a whole different set of functions.

The only thing you have to be cautious
about is to make sure when you're invoking a
particular function, as with any typecast,
is that the particular object supports that
particular function. I usually keep both the
pointer to the object and the pointer to the
function together to make sure that this is done
right. You can also dynamic cast to make sure
you're point to a B object before you do the
->* function call

-Fluden
(from Porto Alegre, Brazil)
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top