Archived

This topic is now archived and is closed to further replies.

function pointers & classes

This topic is 5513 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I''ve got a class and one of the functions takes as a parameter a function pointer. This works just fine if that function is some global one. But if it''s a member of another class the it just doesn''t work. Any idea how to solve this? class Cubemap { void RenderToCubemap( void (*renderFunction)(void) ); ... } this works: Cubemap cm cm.RenderToCubemap( someGlobalFunction ); but this doesn''t cm.RenderToCubemap( someOtherClass.publicFunction ); You should never let your fears become the boundaries of your dreams.

Share this post


Link to post
Share on other sites
quote:
Original post by _DarkWIng_
I''ve got a class and one of the functions takes as a parameter a function pointer. This works just fine if that function is some global one. But if it''s a member of another class the it just doesn''t work. Any idea how to solve this?


class Cubemap {
void RenderToCubemap( void (*renderFunction)(void) );
...
}

this works:
Cubemap cm
cm.RenderToCubemap( someGlobalFunction );

but this doesn''t
cm.RenderToCubemap( someOtherClass.publicFunction );



Type safety -- it''s the same reason you can''t pass a function with different parameters or that returns a value. It doesn''t match your declaration. Think about when you use a nonstatic member function of a class -- when you call it, you are implicitly passing the object you are using the function on to the member function (it''s just hidden from you).

A.MyMethod()

may look like it takes no parameters, but internally it''s passing the address of the object A to the function.

If you were to attempt to store the address of a member function to a global function pointer, just think of the problems you''d have -- you wouldn''t be able to associate the call with an object.

They are two completely different types of pointers, and you can''t directly convert between the two. If you want a pointer to a member function use the syntax

Returntype ( YourClasstype::*MethodPointerName )( explicit parameters );

Share this post


Link to post
Share on other sites
Stoffel : TNX, but I already read that page and stuff describe there just doesn''t work for me.
Matt Calabrese : If I understand this right, I would have to create a function for every diferent class/function that has to call this function, or am i totaly off here? Would you be so nice and write a quick example?

You should never let your fears become the boundaries of your dreams.

Share this post


Link to post
Share on other sites
Not for every method, just every method type, just like with functions. Here're some examples. If you need more to understand, just ask:


  class MyClass1
{
public:
void DoSomething() const;
int DoSomethingElse() const;
};

class MyClass2
{
public:
void DoSomething() const;
};

int main()
{
void (MyClass1::*SomeMethod)() const = MyClass1::DoSomething; // Will work

void (MyClass1::*SomeMethod)() const = MyClass2::DoSomething; // Will not work


void (MyClass1::*SomeMethod)() const = MyClass1::DoSomethingElse; // Will not work


return 0;
}


[edited by - Matt Calabrese on November 8, 2002 3:27:51 PM]

Share this post


Link to post
Share on other sites
No, but a member function pointer needs to have an object in order to be called. The difference between free functions and member functions are that the member functions have an "invisible" parameter called "this" passed along to it. It''s just that instead of passing it as an argument:
memFun (&object);
you pass it by "calling" the member on that object:
object.memFun ();

So if you use a member function pointer, you have to have an object and use the pointer-to-member operator:
(object.*memFunPtr) ();

Share this post


Link to post
Share on other sites
OK, I understand now why I need ClassName::*functionName() stuff but the thing is it still doesn''t work. I just get different error.


Class B {
Call( void (*callie)(void) ) {
callie();
)
}

Class A {
void Render() {
// do some stuff here
}
void Play() {
// 1) original idea
instanceOfB.Call( Render );
// 2) idea from www.function-pointer.org
instanceOfB.Call( A::*Render );
// 3) from what all of you wrote
void (A::*myFunction)() = A::Render;
instanceOfB.Call( myFunction );
}
B instanceOfB;
}


What do I need to rewrite to make this work?


You should never let your fears become the boundaries of your dreams.

Share this post


Link to post
Share on other sites
quote:
Original post by _DarkWIng_
OK, I understand now why I need ClassName::*functionName() stuff but the thing is it still doesn''t work.

Actually, you apparently don''t understand. Using your example, for B::Call to be able to accept one of A''s methods its argument (callie) would need to be of type (void A:: *)(void), not (void *)(void). No amount of syntactic gymnastics will alter that requirement.

Besides, what does A need B for? It can maintain a pointer to any of its own functions and call them directly. What is the real "problem" you''re trying to solve?

Share this post


Link to post
Share on other sites
Nope, you're still not understanding.

There are a lot of errors in your example code, so I'm not going to touch on it directly considering it's hard to tell which were typos and which you really don't understand.

You can't convert from a member function pointer to a function pointer. We went over all of the reasons why above. If you STILL don't understand, just think about it like this -- a nonstatic member function needs an object to deal with because you will be using datamembers of an instance of the class. If you pass just the member function pointer and try to convert it directly to a regular function pointer, you are making it sytanticly impossible to call with an associated object (without a cast, which you should NOT do), and not only that, your program would most likely crash because any member data that the member function refers to would attempt to be accessed through garbage on the stack where the "this" pointer would normally be ( i think that's what'll happen, but you might even get an error prior ), much in the same way if you were to attempt to dereference a pointer (or worse, write to value pointer to by it) that you didn't initialize. Not good.

Just think rationally about what you're doing and think about why you can't do what you're attempting. Just imagine what's going on internally and you'll better understand it. We're explaining it as best we can, but unless you try to think about exactly what's happening you're just gonna have more an more questions. Read over what we've said a few times and really think about what's going on in memory and most of your questions you can probably answer yourself.

[edited by - MAtt Calabrese on November 9, 2002 4:34:29 AM]

Share this post


Link to post
Share on other sites
OK, I give up. I "think" I understand why it doesn''t work. Member functions need some class(instance) to operate on. It can''t be just called on its own. Right? I still haven''t got a clue how to make it work. I''ll try to find another way.

"...What is the real "problem" you''re trying to solve?..." I was trying to make function to create(render) cubemap with a simple call cubemapInstance.RenderCM( worldRenderFunction,... ); So RenderCM(...) would just have to orient camera & call worldRenderFunction 6 times to create cubemap. Plain and simple but not as easy as I tought . Now I guess I will have to break apart RenderCM into a few functions and call them from other class.


You should never let your fears become the boundaries of your dreams.

Share this post


Link to post
Share on other sites
Pointers to member functions are not pointers to function : the code

#include <iostream>

class Foo
{
public:
void foo() {}
virtual void bar() {}
static void baz() {}
};

void quux() {};

int main()
{
std::cout << sizeof( &Foo::foo ) << ' '
<< sizeof( &Foo::bar ) << ' '
<< sizeof( &Foo::baz ) << ' '
<< sizeof( &quux ) << std::endl;
}
prints out, on my system, 8 8 4 4 , proving that pointers to member function and pointers to function are inherently incompatible - they do not even have the same size.

No amount of casting will fix that.

- edit - to solve your problem, consider using function objects (a.k.a functors), since you control both ends of the API. boost::function is a good point to start - see boost link in sig.

Documents [ GDNet | MSDN | STL | OpenGL | Formats | RTFM | Asking Smart Questions ]
C++ Stuff [ MinGW | Loki | SDL | Boost. | STLport | FLTK | ACCU Recommended Books ]


[edited by - Fruny on November 9, 2002 6:10:41 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Fruny
proving that pointers to member function and pointers to function are inherently incompatible - they do not even have the same size.
[edited by - Fruny on November 9, 2002 6:10:41 AM]



That part shouldn't be correct. A pointer to a location in memory is a pointer of a location in memory and always has the same size. Your compiler shold not return two different sizes unless it's on crack. I checked on msvc++ 6 just in case and it returns the same size as I expected. I'm not sure, but I think that it's standard that all pointers must be of the same size -- if not, then it still doesn't make sense why you would ever want them to be different sizes as it would be pointless. The only thing I can think of that might be happening is you compiler might be storing both the memory location and the integer vtable function pointer offset to account for polymorphism when using the method pointer, but I'm pretty sure that's NOT a part of the standard ( and shouldn't be, because then all of the methods in that class would have to take up the extra space even if they aren't defined as virtual so that they are the same size ). It would also be bad because since it's not a part of the standard (unless I'M the one on crack right now ), then that would mean compilers that follow the standard would only allow for static linking with method pointers (which they do) but the method I described would allow for dynamic linking, but it can potentially screw up the results if the programmer WANTED static linking. Anyways, I'm rambling on about what might be happening, but I'm honestly not sure. What Fruny is saying about the sizes of the pointers, to my knowledge, should not be correct. Anyone with another explanation, please bring it forward!


EDIT:

Hmm, I decided to search myself on the topic and already I'm getting VERY mixed results. One site claims that method pointers should actually take up 12 bytes on 32-bit address machines and that if they don't they aren't following the standard! They mention what I was talking about in my post about the vtable offset. If 3 * sizeof( void* ) is the standard, then I say f*ck the standard, I want static linking unless I say otherwise, and if I make a pointer I want a POINTER not all that other bullship to bloat my code. I sure hope they're not correct. Where's a place to find out EXACTLY what the standard is?

http://www.geocrawler.com/archives/3/361/1993/10/0/2026036/

[edited by - Matt Calabrese on November 9, 2002 7:01:04 AM]

Share this post


Link to post
Share on other sites
The C++ Standard ( $18 in electronic form on ANSI's website ), makes no mention of how the language should be implemented, only of what the language is . vtbls, even though they are a de-facto standard, are never mentioned - you might find a compiler that doesn't use them.

C++ has no ABI - there is no constraint on the binary representation of language constructs - which is why I specified 'on my system' (g++ 3.2).

Pointers to member functions are not required to be implemented as addresses. They are often implemented as structs carrying type information in addition to the function address. Virtual function pointers hold an offset instead of an address, which could, once again, be of any size.

This brings us back to the topic of this thread - the lack of convertibility - which is explained by the fact that we are dealing with different entities (which, BTW, use different call syntax : quux() vs. f.*foo() )

g++ 3.2 on cygwin-386 yields 8 8 4 4
WorkShop Compilers 5.0 98/12/15 C++ 5.0 on Solaris 7 yields 8 8 4 4 (after tweaking around the lack of iostreams)
MIPSpro Compilers 7.2.1.2m on SGI IRIX 6.5 yields 12 12 4 4
Microsot Visual C++ 7 yields 4 4 4 4 (after tweaking around rejection of &Foo::baz and &Foo::quux in sizeof)

Edit - in reply of Matt's edit

Well, when you're taking a pointer to a variable, you do get a memory address. When you take a pointer to a member function, you do get a pointer to a member function - something that ACTS as you desire, not necessarily something that has the internal structure you expected it to have (don't even get started about the private members of classes. Just because you don't know why or what they are doesn't mean they're 'bloat').

So, let me put the emphasis on the fact that a pointer to a member function is not a 'memory address'. It is a pointer to member function. If you're unhappy with the way it is implemented, roll your own out, C style. Then compare the bloat, robustness and convenience of the two. Only then will you be entitled to scream about code bloat.

Documents [ GDNet | MSDN | STL | OpenGL | Formats | RTFM | Asking Smart Questions ]
C++ Stuff [ MinGW | Loki | SDL | Boost. | STLport | FLTK | ACCU Recommended Books ]


[edited by - Fruny on November 9, 2002 7:34:29 AM]

Share this post


Link to post
Share on other sites
If that is true, then what is the standards claim on polymorphism through "method pointers?"

With these verying implementations, some account for it and some don''t! Compilers should be free to their own implementation, but whether or not method pointers work with polymorphism should not. I can only imagine the porting issues! What if you don''t want dynamic linking on an object through a method pointer call? There''s nothing you can do! They''ve gotta have some stand on it? IMO static linking is the best way to go on this -- if I want dynamic linking I''ll just use templated functors. I really don''t want to go and waste an extra 9 bytes per method pointer for dynamic linking when in many cases it isn''t necissary...

Share this post


Link to post
Share on other sites
quote:
Original post by _DarkWIng_
I was trying to make function to create(render) cubemap with a simple call cubemapInstance.RenderCM( worldRenderFunction,... ); So RenderCM(...) would just have to orient camera & call worldRenderFunction 6 times to create cubemap. Plain and simple but not as easy as I tought . Now I guess I will have to break apart RenderCM into a few functions and call them from other class.

In other words, you want to call an externally defined function to operate on/using internal data.

typedef (void *RENDERFUNCTION)( long *, long * );
 
void worldRenderFunction( long * some_data, long * some_more_data )
{
// whatever
}
 
void Cubemap::Render( RENDERFUNCTION rf )
{
rf( data, more_data );
}

You can vary all the types and number of arguments; this is an abstracted example just to give you an idea of one way to do it. Another is using functors:

struct renderfunctor
{
virtual void operator () ( long *, long * ) = 0;
};
 
struct rendercubemap : public renderfunctor
{
virtual void operator() ( long * some_data, long * some_more_data )
{
// whatever
}
};
 
void Cubemap::Render( const renderfunctor & rf )
{
rf( data, more_data );
}

Share this post


Link to post
Share on other sites
quote:
Original post by Matt Calabrese
If that is true, then what is the standards claim on polymorphism through "method pointers?"

With these verying implementations, some account for it and some don't! Compilers should be free to their own implementation, but whether or not method pointers work with polymorphism should not. I can only imagine the porting issues! What if you don't want dynamic linking on an object through a method pointer call? There's nothing you can do! They've gotta have some stand on it? IMO static linking is the best way to go on this -- if I want dynamic linking I'll just use templated functors. I really don't want to go and waste an extra 9 bytes per method pointer for dynamic linking when in many cases it isn't necissary...

http://cpptips.hyperformix.com/cpptips/ptmf

The canonical solution is to use functors anyway.

[edited by - Oluseyi on November 9, 2002 7:46:52 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Matt Calabrese
If that is true, then what is the standards claim on polymorphism through "method pointers?"

With these verying implementations, some account for it and some don''t! Compilers should be free to their own implementation, but whether or not method pointers work with polymorphism should not. I can only imagine the porting issues! What if you don''t want dynamic linking on an object through a method pointer call? There''s nothing you can do! They''ve gotta have some stand on it? IMO static linking is the best way to go on this -- if I want dynamic linking I''ll just use templated functors. I really don''t want to go and waste an extra 9 bytes per method pointer for dynamic linking when in many cases it isn''t necissary...


First note - the URL you linked refer to a thread from 1993. The C++ standard was finalized in 1998 - five years later. It accurately referred to that as a bug.

Second note - templated functions are not dynamic typing (not ''linking'' either) - they''re compile-time polymorphism, static typing. Virtual functions are dynamic typing (though not to the extent of SmallTalk or Objective C)

Third note - on waste - How much do you think you ''waste'' from data alignment on qword boundaries that is mandated by 32-bit processors

There are no porting issues, since the C++ standard is a source specification. Theoretically (if we had standard-compliant compilers) standard C++ source should compile the same with any compiler. If you correctly referred to the size of a void* pointer as sizeof( void* ) instead of hard-coding 16, 32, 64 or whatever is currently valid on your platform, on your compiler, then you''re fine. This has always been true. The size of a short, int, long aren''t exactly defined either, only minimum sizes and their relative ordering.

Keep that in mind : the size of a type is sizeof Type, nothing else.

On the other hand, the lack of an ABI prevents binary interoperability - a library compiled with a given compiler will not necessarily link correctly with programs compiled with another compiler. You see that frequently even on gamedev.net when people want to use DirectX with g++ or Borland C++. It is a problem, which is not going away until and unless a C++ implementation distinguishes itself enough that others adopt its binary interface. Will it be MSVC, Comeau C++, Metrowerks Codewarrior, GNU C++, Visual Age C++, Intel C++ on the x86 ? I don''t know.

Finally, how do you enforce a binary API on different architecture (Motorola, Mips ...)

Documents [ GDNet | MSDN | STL | OpenGL | Formats | RTFM | Asking Smart Questions ]
C++ Stuff [ MinGW | Loki | SDL | Boost. | STLport | FLTK | ACCU Recommended Books ]

Share this post


Link to post
Share on other sites
quote:
Original post by Oluseyi
The canonical solution is to use functors anyway.

[edited by - Oluseyi on November 9, 2002 7:46:52 AM]


Yup, that's what I was saying.

Anyways, is it specifically stated whether or not method pointers are supposed to work with polymorphism?

Edit: (too many of us are posting in here at the same time, I can't keep up with the edits and posting, etc. )

First off -- linking was a mistype, but it was a mistype for binding not typing (it's 4:45 AM here and i've been up for almost 20 hours stright ),

second, I said templated functor, not templated function. I wouldn't have gotten very far if I didn't realize templating was compile-time

When I was talking about portability I was refering to polymorphism with method pointers, but apparently it is standard to have it work with polymorphism, which is what I was asking earlier. If it wasn't then on some compilers virtual method calls would be staticly bound and on others, dynamically, which would be problemmatic. As I said, I now notice that it is standard that method pointers work with polymorphism, so everything works out fine and dandy.

Thanks for those responses, you actually answered a question that has been bugging me for a while but I never thought to ask for some reason.

Anyways, I think we got off-topic...

[edited by - Matt Calabrese on November 9, 2002 8:08:44 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Matt Calabrese
If that is true, then what is the standards claim on polymorphism through "method pointers?"

In what way? The C++ Standard describes the semantics that a programmer can expect from dynamically resolved function calls (BTW, "method" is the incorrect terminology for C++). There is no attempt to impose an implementation mechanism.
quote:

Compilers should be free to their own implementation, but whether or not method pointers work with polymorphism should not.

That''s about right.
quote:

What if you don''t want dynamic linking on an object through a method pointer call?

Since the Standard has nothing to say about linking issues, I''ll assume you mean dynamic despatch. If you don''t want dynamic despatch, you don''t make a function virtual.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by _DarkWIng_
I''ve got a class and one of the functions takes as a parameter a function pointer. This works just fine if that function is some global one. But if it''s a member of another class the it just doesn''t work. Any idea how to solve this?


class Cubemap {
void RenderToCubemap( void (*renderFunction)(void) );
...
}

this works:
Cubemap cm
cm.RenderToCubemap( someGlobalFunction );

but this doesn''t
cm.RenderToCubemap( someOtherClass.publicFunction );


You should never let your fears become the boundaries of your dreams.


Can''t you make the publicFuntion a friend-function to someOtherClass?

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan
(BTW, "method" is the incorrect terminology for C++).

I've always been told to call them methods, and in all of the books I've read they call them methods. What should I call them? Just member functions? (no that wasn't sarcastic, I really am curious if there is a reason not to call them methods because I have specifically been taught TO call them methods)
quote:

Since the Standard has nothing to say about linking issues, I'll assume you mean dynamic despatch. If you don't want dynamic despatch, you don't make a function virtual.
Yup, I meant dispatch, I clarified that in my previous response, though this topic is rather active you prolly replied before then.

However -- you missed my point. There are times that you call a virtual function like this:


  #include<iostream>
class A
{
public:
virtual void Foo() { std::cout << "Parent\n"; }
};

class B
: public A
{
public:
virtual void Foo() { std::cout << "Child\n"; }
};

int main()
{
B Something;
Something.A::Foo(); // This is what I'm refering to!

// You explicitly call the 'A'

// version of Foo, which is impossible

// to do with member function pointers

// because dynamic dispatch is assumed

return 0;
}


Get it?

EDIT: Added function bodies to make my point more clear

[edited by - Matt Calabrese on November 9, 2002 8:38:02 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Matt Calabrese
I''ve always been told to call them methods, and in all of the books I''ve read they call them methods.

C++ books? The only one of my C++ books which mentions "method" in the index is Advanced C++ (Coplien) and does so with regard to Smalltalk, not C++.
quote:

What should I call them? Just member functions?

Yep.
quote:

However -- you missed my point.

Yes, sorry.
[snip example]

Get it?
Yes, I see what you mean and you''re right. However, the thinking seems flawed. When you mark a function "virtual", you are saying to the compiler "despatch this method on the dynamic type of the first argument". The fact that using the dot operator actually performs static resolution is a bit of an anomaly (possibly even bogosity). So, you seem to be saying both "do dynamic despatch" and "do static despatch" which is a rather odd thing to want to say. You would avoid this sort of problem by not weaving such an ambiguity into a design, so I think it''s an artificial problem. To be a *real* problem, it has to prevent you from solving real-world problems in an effective manner.

Share this post


Link to post
Share on other sites
In Java you call them methods and in C++ you call them functions. I seem to remember that calling member variables, attributes, is something that got introduced with Java as well.

Share this post


Link to post
Share on other sites