Jump to content
  • Advertisement
Sign in to follow this  
hick18

Is this ok? [c++ member functions]

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

Although this works, Im wondering if its actually ok to do. Im not really sure how member funtion pointers work under the hood. I assume its an offset from the beginning of the class.
class Window {};
class Derived{
public:
	void Custom(){}
};
typedef void (Window::*MemFunction)();
MemFunction f = static_cast< MemFunction >(&Derived::Custom);


Share this post


Link to post
Share on other sites
Advertisement
Generally doing any sort of casting on function pointers is a bad idea. Occasionally, you might need to do it, but generally avoid it if at all possible.

Also, it appears that you don't really understand how member functions work in C++; (it's a very complex topic, so you're certainly not alone) here's a taste of what you can expect.

Hopefully you should have a better idea of why casting is such an iffy idea.

EDIT: I should probably also mention that the specific implementation of the vtable is entirely compiler-dependent and the above link makes no references to the calling behavior of non-virtual member functions, which are technically another beast entirely. If you really want to implement delegates, look into something called functionoids/functors. It's still somewhat shaky ground, but better than the alternative.

Share this post


Link to post
Share on other sites
No, I'm pretty sure that won't work. What if you tried to apply that member function pointer to a different Window subclass that didn't have that member, or had a different one?

Share this post


Link to post
Share on other sites
I would have to question if you have tested that code (I have not), I would suspect the cast requires a reinterpret_cast.

If we ignore how the cast is done, then yes it is valid. What you do with the function pointer after the cast though will determine if it is valid and defined.

After looking in the standard I am still unsure if the static_cast is fine as 5.2.9.9 talks about converting from derived to base yet the conversion section it points to refers to base to derived. Then goes to imply it is fine by stating
Quote:
Note: although class B need not contain the original member, the dynamic type of the object on which the pointer to member is dereferenced must contain the original member


Quote:

5.2.9.9
An rvalue of type “pointer to member of D of type cv1 T” can be converted to an rvalue of type “pointer to member of B of type cv2 T”, where B is a base class (clause 10) of D, if a valid standard conversion from “pointer to member of B of type T” to “pointer to member of D of type T” exists (4.11), and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.63) The null member pointer value (4.11) is con- verted to the null member pointer value of the destination type. If class B contains the original member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the original member. Otherwise, the result of the cast is undefined. [Note: although class B need not contain the original member, the dynamic type of the object on which the pointer to member is derefer- enced must contain the original member; see 5.5. ]



Quote:

4.11.2
An rvalue of type “pointer to member of B of type cv T,” where B is a class type, can be converted to an rvalue of type “pointer to member of D of type cv T,” where D is a derived class (clause 10) of B. If B is an inaccessible (clause 11), ambiguous (10.2) or virtual (10.1) base class of D, a program that necessitates this conversion is ill-formed. The result of the conversion refers to the same member as the pointer to member before the conversion took place, but it refers to the base class member as if it were a member of the derived class. The result refers to the member in D’s instance of B. Since the result has type “pointer to member of D of type cv T,” it can be dereferenced with a D object. The result is the same as if the pointer to member of B were dereferenced with the B sub-object of D. The null member pointer value is converted to the null member pointer value of the destination type.52)


[Edited by - dmail on April 16, 2010 11:09:49 AM]

Share this post


Link to post
Share on other sites
Well, this is how I understand things. Which is why i think it shoud be ok. Maybe you could tell me if its right or not

Writing a Custom function for the Derived type such as,


void Derived::Custom(){}




Is translated into,


void Custom( void* thisPointer ){}




where the call to Derived::Custom() of,


Derived d;
d.Custom();




is translated too,


Derived d;
Custom(&d);




and so when taking the pointer to a member function, what you're really doing is taking a pointer of the function,


void Custom( void* thisPointer ){}




Where, when calling using special member function pointer syntax of,


(ObjectInstance->*MemberFunction)();




it passes the address of the objectInstance to the function as the this pointer, so that thisPointer = &ObjectInstance

So thinking about it in those terms, the code should work fine. That is unless I have all the above horribly wrong. In that as
long as i call member functions with types of the member functions class type, or higher in the hierarchy, all should be fine.

Share this post


Link to post
Share on other sites
Learn it, love it.

Quote:
Which is why i think it shoud be ok.

Common sense and C++ are separate subjects.

When it comes to function pointers, the number of special cases and obscure rules goes through the roof. I remember that it's possible for same function to generate different layouts in different compilation units of same project. There is a reason why boost function and bind are such mess of code, and even they don't cover everything, since it would cause exponential explosion of special cases.

IIRC, casts and function pointers simply don't mix.

Personally, I find that function pointers are best left in C, whereas in C++ polymorphic functions perform the same role. And delegates, as popularized by C++, have next to no place in C++, as demonstrated by various signal/slot libraries or boost::signal, all of which are a horribly tangled mess of working around threading issues and memory management, often just leaving anything non-trivial to mostly luck.

IMHO, boost function (slowly coming to standard library as well) should be used instead.

Share this post


Link to post
Share on other sites
Im not really trying to achieve anything. I just noticed it being used in the MFC headers(Or at least what I believe it to be used in), and was wondering how they got it to work.

I believe they use macros to do what i was doing above.

For example, their classes all derive from a common window class CWnd. And when they derive from that with some custom class such as, they use macros to get the correct member function pointers


BEGIN_MESSAGE_MAP(CClassView, CDockablePane)
ON_WM_SIZE()
END_MESSAGE_MAP()




where OnSize is declared for a window derived from CWnd as


void OnSize(UINT nType, int cx, int cy);




and ON_WM_SIZE() expands to


#define ON_WM_SIZE() { WM_SIZE, 0, 0, 0, AfxSig_vwii, (AFX_PMSG)(AFX_PMSGW) (static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, int, int) > ( &ThisClass :: OnSize)) },




Which seems to be very similar to what I was doing. That is, casting a derived class (ThisClass), and then taking a function pointer

Share this post


Link to post
Share on other sites
MFC can get away with that cast because they put restrictions on inheritance of classes from CWnd: you can't inherit from two or more classes that inherit directly or indirectly from CWnd and the class that inherits from CWnd must be the first class in the inheritance list. If you fail to follow these guidelines the message map will blow up messily.

Share this post


Link to post
Share on other sites
Actually I have only just noticed that your "Derived" class does not inherit from Window. Just shows one of the problems of _example_ code rather than actual code.

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!