views:

1155

answers:

9

I'm used to thinking of member functions as just being a special case of normal functions, where member functions have an extra parameter at the beginning of their parameter list for the 'this' pointer, that is, the object on which the member function is supposed to act. I've used boost::function this way in the past and never encountered any problems:

boost::function f<(void)(MyObject*, int, int)> = &MyObject::method_that_takes_two_ints;

But I've seen this syntax for member-function pointers:

void (MyObject::*f)( int, int ) = &MyObject::method_that_takes_two_ints;

In this syntax, the 'this' parameter is not visible. Which got me wondering if under the hood pointer-to-member-functions are really a separate beast, and that boost was taking care of details for me.

What does the standard dictate about the placement of the 'this' parameter? Perhaps just on my compiler the extra 'this' argument comes first, and maybe on other compilers it could be on the end? Am I just lucky that my way of thinking is consistent with how my compilers (GCC4, VS2005) handle it? Are pointer-to-member-functions always just a special case of pointer-to-functions with an extra parameter or can the compiler implement them differently?

+10  A: 

The standard says next to nothing about where the this pointer should be placed, and in fact it is fairly common to use a different calling convention for member functions. (So the 'this' pointer is not just an extra first argument, it's actually stored in a different location than the first arg usually is)

In particular, MSVC uses the thiscall calling convention for member functions, and stdcall elsewhere. http://www.hackcraft.net/cpp/MSCallingConventions/#thiscall describes the differences between them, but note that thiscall stores the this pointer in the ECX register, while stdcall stores all parameters on the stack.

You're definitely better off treating them as completely distinct types. A pointer to a member function is not just a pointer to a function with an extra parameter.

jalf
+2  A: 

Yes, pointers-to-functions and pointers-to-members are completely different beasts. Pointers to members need to be given an object instance to be dereferenced using the ->* or .* operators. There is no this parameter used when making a pointer-to-member because this is determined when the pointer to member is used (the object on the left of ->* or .*).

Note the there is probably less of a difference between a pointer-to-member function and a pointer-to-member variable than there is between a pointer-to-member function and a regular function pointer.

Typically member functions and regular functions can have completely different calling conventions so you can't cast between them.

Charles Bailey
+1  A: 

They are definitely distinct types and any assumptions you make will be platform/compiler specific.

This page has more information about the implementation of member function points than I ever wanted to know, including implementation details for numerous popular compilers.

Dave Ray
+9  A: 

The this pointer is not stored along a pointer to member (member function pointers are a special case of this). If you just do

void (MyObject::*f)( int, int ) = &MyObject::method_that_takes_two_ints;

then what is stored is just the information which member function should be called on a objet which you later have to provide. If you want to call it, you have to pass an object along, where the compiler will get the this pointer from.

MyObject o; (o.*f)(1, 2);

A member function pointer is just a member pointer whose type (that's pointed to) is a function type. The Standard says that member function pointers do not have their own "member function type" that they point to and that would somehow include the this pointer type.

int main() {
    typedef void fun() const;
    fun MyObject::*mem_function_ptr = 
        &MyObject::const_method_that_takes_two_ints;
}

fun in that code is the function type. The type that a "normal" function has. A pointer-to-function, as opposed to a member-function-pointer, is just a pointer to a function having that type:

void foo() { cout << "hello"; }
int main() {
    typedef void fun();
    fun * f = &foo;
}

While a pointer-to-member-function has the additional member-pointer level on-top of that function type.

Something about the this pointer and how it relates to the object that it points to (not technical, just the theoretical stuff):

Each member function has a hidden parameter called the implicit object parameter which has type MyObject& or MyObject const& depending on whether you have a const or nonconst member function. The object that you call the member function on, o, is the implied object argument, which is passed to the parameter. In the theory of the standard that make up the rules that describe how member functions are called, the implicit object parameter is a first hidden parameter. That's conceptual, and doesn't mean it's the real case in implementations. The implied object argument is then bound to that implicit object parameter, possibly causing implicit conversions (so if you call a const member function on a non-const object, a qualification conversion converts from MyObject to MyObject const&. That is what makes non-const functions a better choice than const functions to call, for a non-const object). For example, one can say in this code:

struct A {
    operator int() const { return 0; }
};

int main() { 
    A a;
    int i = a; // implicit conversion using the conversion function
}

That the implied object argument a of type A is bound to the implicit object parameter of type A const&, whose object is then pointed to by the this pointer having the type A const* here. Important to note is that the implicit object parameter is only a theoretical construct, to formalize how the rules for calling a member function are made up (and constructors do not include them), while the this pointer is actually existent. this is a pointer, because when this was introduced, C++ didn't have references yet.

I hope that will help you understand the matter.

Johannes Schaub - litb
impressive answer.
mahesh
A: 

To supplement everyone else's answer, Boost.Function works by specializing the assignment operator on member function pointers, to allow it to detect when you have passed one. When you call that function, it will internally reinterpret it to the proper method of calling the member function pointer ((obj->*fun)(args)).

coppro
+7  A: 

An excellent article on member function pointers is CodeProject's Member Function Pointers and the Fastest Possible C++ Delegates. This article describes member function pointers from the simple cases all the way through virtual member function pointers with multiple inheritance. As a bonus, it provides an implementation of delegates that can be really useful.

Greg Hewgill
+3  A: 

Note that the size of a pointer-to-member-function may be different using different compilers.

Another thing to note, as written in The Old New Thing blog:

The size of a pointer-to-member-function can change depending on the class.

dalle
+1  A: 

To answer all questions: Yes, they're special pointers, different from ordinary pointers. Yes, boost::function recognises them.

The standard says nothing about the internal details of call stacks. In fact, many compilers may use integer rergisters, floating point registers, and/or the stack depending on the actual argument list. A 'this' pointer is just one more special case.

Boost::function solves this by using two code paths internally. You can see this by inspecting the call stack for the two cases. If your boost::function stores a pointer to member function, the operator() will split the argument list. The first argument is used as the object on which the member function is called with the remaining arguments.

MSalters
A: 

Hi, I think you might find this link quite interesting:

http://www.parashift.com/c++-faq-lite/pointers-to-members.html

It's a very good description of everything you'd want to know about pointer-to-members.

Ray Hidayat