Member function pointers?

Started by
18 comments, last by CapThunderNutz 8 years, 5 months ago

The downvote was a mistake on my part. ph34r.png Since I couldn't undo the downvote, I had upvoted post #9 to compensate.

Advertisement

Ah, no dramas, cheers. I was worried I've done something wrong that I did not understand :P

It's all about how functions are stored.

Thanks for the awesome example! I definitely appreciate it

I see that the function pointer of AnotherClass is: void (TestClass::*fMyFunctionPtr)()
Would it be possible to set the function pointer if it was just: void (*fMyFunctionPtr)()
or does it need to include the AnotherClass type?

How would it be possible to do the same if AnotherClass was really AnotherStruct?
Looking something like this, where AnotherStruct is kept 'pure' (no adding of outside classes or etc)?
//In AnotherStruct.hpp
typedef struct AnotherStruct
{

  struct AnotherStructCallback *callback;

} AnotherStruct;

typedef struct AnotherStructCallback
{

  void (*MyFunctionPointer)();

} AnotherStruckCallback

//============================

//In TestClass header file
void Init(AnotherStruct *anotherStruct);
void MyFunction();

//In TestClass imp file
void Init(AnotherStruct *anotherStruct)
{
    //Assign the MyFunctionPointer to the member method MyFunction
    anotherStruct->callback->MyFunctionPointer = ?????;

}

From your previous code, simply do :


anotherStruct->callback->MyFunctionPointer = MyFunction;

From your previous code, simply do :

anotherStruct->callback->MyFunctionPointer = MyFunction;

Unfortunately when using the struct code, I get a syntax error unless MyFunction is static. I get:
a value of type "void (TestClass::*)()" cannot be assigned to an entity of type "void (*)()"

If I am to do:

anotherStruct->callback->MyFunctionPointer = &this->MyFunction;

I get the error:
ISO C++ forbids taking the address of a bound member function to form a pointer to member function. Say '&TestClass::MyFunction' [-fpermissive]

If you use C++11 onward, you should use std::function and combine it with std::bind.


class AnotherObject
{
public:
   std::function<void(void)> callback;
};

class TestObject
{
public:
   void MyFunction() {};
};

int main()
{
   AnotherObject ao;
   ao.callback = std::bind(&TestObject::MyFunction, &ao);
   ao.callback();
}


I see that the function pointer of AnotherClass is: void (TestClass::*fMyFunctionPtr)()
Would it be possible to set the function pointer if it was just: void (*fMyFunctionPtr)()
or does it need to include the AnotherClass type?

For type correctness it needs to include AnotherClass as the type definition.

START - HORRIBLE CODE (I only show this for learning purposes, don't actually do this)

Of course, C++ allows you to be evil by letting you cast everything into everything else. I suspect how you go with this will vary from compiler to compiler, and if you treat warnings as errors, then I suspect the code will not compile anywhere. If you were to directly cast it as shown below and execute the function, I'm not sure exactly what will happen, but I strongly suspect it would be deemed unknown behaviour.


void (*MyFunctionPtr)() = (void (*)())(&TestClass::MyFunction);

MyFunctionPtr();

Now if you slightly modify this code to look like the snippet below it will work if you get the address from the object instance directly, but it basically ignores the standard and has the same problems of what will the compiler actually do. I would not recommend you do this any any production code. (Note for this code to compile, you need to specify the -fpermissive compiler option for g++ and mingw.) I don't know if this works in either Clang or Visual Studio.


void (*MyFunctionPtr)() = (void (*)())(&testObject.MyFunction);

MyFunctionPtr();

END - HORRIBLE CODE

How would it be possible to do the same if AnotherClass was really AnotherStruct?

The previous examples that I showed will work for either Classes or Structs. In C++ there are only two differences between structs and classes. This link explains it well: http://stackoverflow.com/questions/92859/what-are-the-differences-between-struct-and-class-in-c.

How would it be possible to do the same if AnotherClass was really AnotherStruct?
Looking something like this, where AnotherStruct is kept 'pure' (no adding of outside classes or etc)?

I'm not sure what you mean by pure. If you keep it in C++ land, then you don't need to change anything. If you go to C land, then the concept of classes don't exist. The cleanest way you can do that will be to be to create a wrapper type (or use stl::function) that is cast to a void pointer for storage in you C struct. If you then need to execute the code function pointer, you will need a function in C++ land that will cast the pointer back to the correct type and subsequently invoke the function call.

If this is really what you want to do, I would recommend you look at perhaps other design patterns, or do message / event passing between C and C++ code blocks.


START - HORRIBLE CODE (I only show this for learning purposes, don't actually do this)



Of course, C++ allows you to be evil by letting you cast everything into everything else. I suspect how you go with this will vary from compiler to compiler, and if you treat warnings as errors, then I suspect the code will not compile anywhere. If you were to directly cast it as shown below and execute the function, I'm not sure exactly what will happen, but I strongly suspect it would be deemed unknown behaviour.

void (*MyFunctionPtr)() = (void (*)())(&TestClass::MyFunction);

MyFunctionPtr();

Now if you slightly modify this code to look like the snippet below it will work if you get the address from the object instance directly, but it basically ignores the standard and has the same problems of what will the compiler actually do. I would not recommend you do this any any production code. (Note for this code to compile, you need to specify the -fpermissive compiler option for g++ and mingw.) I don't know if this works in either Clang or Visual Studio.

void (*MyFunctionPtr)() = (void (*)())(&testObject.MyFunction);

MyFunctionPtr();

END - HORRIBLE CODE

Never, I repeat NEVER do this. Function pointer sizes are different depending on wether the function is a (virtual/normal) member function or a top-level function!

I'm not convinced that the second method works. Member functions have an implicit "this" as first argument and regardless of getting the function pointer from the class or (incorrectly) from the object itself the pointer should be truncated by the cast and crash terribly as soon as you use the actual "this" object within the function.

To be fair, casting a member function to a regular function is possible, but is usually not a smart thing to do because it depends on the compiler and if the function is virtual or not etc.


class A
{
public:
   void Method(int x) { cout << x << endl; }
};

void (Func*)(A* this, int x);

int main()
{
   A instanceA;
   Func f = (Func)(A::Method); //or some such evil cast, not sure if i'm missing and address operator, i.e. &A::Method
   f(&instanceA, 5);
}

However, if you're doing this, note that your code is bad and you should feel bad and change it promptly to a good design so you start feeling good because your code is not bad anymore. :)

devstropo.blogspot.com - Random stuff about my gamedev hobby


To be fair, casting a member function to a regular function is possible, but is usually not a smart thing to do because it depends on the compiler and if the function is virtual or not etc.
class A
{
public:
void Method(int x) { cout << x << endl; }
};

void (Func*)(A* this, int x);

int main()
{
A instanceA;
Func f = (Func)(A::Method); //or some such evil cast, not sure if i'm missing and address operator, i.e. &A::Method
f(&instanceA, 5);
}
However, if you're doing this, note that your code is bad and you should feel bad and change it promptly to a good design so you start feeling good because your code is not bad anymore.

Haha that is such a dodgy trick, I love it. :)

For those reading and wondering what is going on, this only works because the stack is being corrupted just right by the non-member function (f) passing in the object instances as the transparent "this pointer" parameter. Absolutely not the sort of thing you do for production code ... unless you are writing an OS without context switching registers or similar. Definitely a no go for user space code.

This topic is closed to new replies.

Advertisement