Jump to content
  • Advertisement
Sign in to follow this  
Makaan

c++ brutal cast = safe?

This topic is 3391 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

Consider the following scenario: class myClass {... void method(); }; typedef void (*proc)(void *); ... myClass object; void *ptr = &object;// cast object to void * proc foo = &myClass::method; // cast class method to type 'proc' (brutal) and now if i do 'foo(ptr);' the 'method' from 'object' will be called. this is equivalent with object.method(); In visual studio 2008 this is allowed and it works with no problems as far as i tested this.Is this absolutely safe with any class type and on other compilers? Thanks Raxvan.

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by Makaan
In visual studio 2008 this is allowed and it works with no problems as far as i tested this.Is this absolutely safe with any class type and on other compilers?
That it works at all is a small miracle, and purely an implementation artefact. This behaviour is neither standard, nor portable, and there are probably many situations where it won't work even under your compiler.

If you actually want to do something like this, you can use member function pointers, or better yet, std::mem_fun or boost::bind.

Share this post


Link to post
Share on other sites
Quote:
Original post by Makaan
Consider the following scenario:

class myClass {... void method(); };

typedef void (*proc)(void *);
...

myClass object;
void *ptr = &object;// cast object to void *
proc foo = &myClass::method; // cast class method to type 'proc' (brutal)

The line proc foo = &myClass::method shouldn't compile. You are missing a (proc*) in the above line?

In any case, yes, the fact that it works is a complete accident and implementation detail of your particular compiler.

An easy way around this is:

class myClass {
// ...
void method();
static void method_func( myClass* self ) { self->method(); }
// ...
};

myClass object;
void* ptr = &object; // implicitly get a void pointer to object.
proc foo = myClass::method_func; // these are type-compatible... probably


As mentioned in the above link, calling conventions _could_ vary between a static member function and a raw C interface that you might end up passing proc to.

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoder
Quote:
Original post by Makaan
In visual studio 2008 this is allowed and it works with no problems as far as i tested this.Is this absolutely safe with any class type and on other compilers?
That it works at all is a small miracle, and purely an implementation artefact. This behaviour is neither standard, nor portable, and there are probably many situations where it won't work even under your compiler.

If you actually want to do something like this, you can use member function pointers, or better yet, std::mem_fun or boost::bind.


thanks for the links, i will try to rethink my design.

It it not a miracle at all the fact that this works, because as far as i know for any c++ implementation uses the same design for OOP(i don't know if there are any exceptions). Any class method is actualy a normal function that has the first argument a pointer to the object (the hidden 'this' keyword) . I can't think of a problem if i manually pass that pointer into the stack and the call the method, the function will simply get fooled.


Edit:
NotAYakk you are right the line proc foo = &myClass::method; will not compile ,
it is just to represent my idea, i fount a way to force the compiler to make that brutal casting.

The static method is iteresting. thanks

Share this post


Link to post
Share on other sites

class Foo {
public:
virtual void method() = 0;
};

class Bar {
public:
virtual void method() {}
};

class Baz: public Bar, public Foo {
public:
virtual void method() { printf("Baz!\n"); }
};
typedef void(Foo::*FooMethod)();
typedef void(Bar::*BarMethod)();
typedef void(Baz::*BazMethod)();

int main(int, char**) {
printf("%d %d %d == %d?\n", (int)sizeof(FooMethod), (int)sizeof(BarMethod), (int)sizeof(BazMethod), sizeof(void*));

return 0;
}

What does the above print out on your system? (not compiled, just tossed out there).

IIRC, not all methods pointers sizeof(void*), even on relatively standard compilers.

Share this post


Link to post
Share on other sites
Quote:
Original post by Makaan
It it not a miracle at all the fact that this works, because as far as i know for any c++ implementation uses the same design for OOP(i don't know if there are any exceptions). Any class method is actualy a normal function that has the first argument a pointer to the object (the hidden 'this' keyword) . I can't think of a problem if i manually pass that pointer into the stack and the call the method, the function will simply get fooled.
Except for the fact that that isn't guaranteed to work on any compiler. You're relying on implementation details which you have no control over and, quite frankly, know nothing about (as they might vary from system to system). Hacking your code up so that it relies on such implementation details is not standard, is not defined, and is not safe.

Share this post


Link to post
Share on other sites
> Any class method is actualy a normal function that has the first
> argument a pointer to the object (the hidden 'this' keyword) .
There are actually two problems with that:
1. depending on the compiler/ABI, member function pointer can be represented differently in memory; member function pointers can be as large as 16 bytes on some compilers.
2. depending on the compiler/ABI, calling convention for regular and member functions may differ; for example, MSVC defaults to thiscall for member functions (this is passed in ecx register, arguments are passed via stack).

Share this post


Link to post
Share on other sites
Quote:
Original post by Makaan
NotAYakk you are right the line proc foo = &myClass::method; will not compile ,
it is just to represent my idea, i fount a way to force the compiler to make that brutal casting.

How did you get that to compile? MSVC seems to reject all the obvious approaches.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Quote:
Original post by Makaan
NotAYakk you are right the line proc foo = &myClass::method; will not compile ,
it is just to represent my idea, i fount a way to force the compiler to make that brutal casting.

How did you get that to compile? MSVC seems to reject all the obvious approaches.


typedef void (*SimpleProc)(void *);

template< class T >
Callback(T * MyObject,void (T:: *proc)())
{
obj= (void *)MyObject;

void (T:: *aux)() = proc;
void * adr = ((void *)&aux);
foo = *((SimpleProc *)adr); //uber brutal cast
}
and voila , 'foo(obj)' :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!