3

I'm trying to wrap my head around pointers to member functions and am stuck with this example:

#include <iostream> class TestClass { public: void TestMethod(int, int) const; }; void TestClass::TestMethod(int x, int y) const { std::cout << x << " + " << y << " = " << x + y << std::endl; } int main() { void (TestClass::*func)(int, int) const; func = TestClass::TestMethod; TestClass tc; tc.func(10, 20); return 0; } 

What I think the code should do:

  • In the first line of main I declare a pointer to a member function of class TestClass, which returns nothing/takes two int's and is declared const, called func.
  • The second line assigns the member-function TestMethod (of class TestClass) to func, which satisfies these criteria.
  • The forth line creates an TestClass-object called tc.
  • The fifth line tries to call the member function pointed to by func on the TestClass-object tc.

I get two compilation errors:

  • Instead of assigning TestClass::TestMethod to func. The compiler tries to call TestClass::TestMethod (even though it's not static, therefore throws an error):

    testPointerToMemberFunc.cpp:14:21: error: call to non-static member function without an object argument func = TestClass::TestMethod; ~~~~~~~~~~~^~~~~~~~~~ 
  • The compiler tries to call a function named func on tc, instead of the function, pointed to by func. To me this seems, like func isn't declared the right way (as a pointer to a member function):

    testPointerToMemberFunc.cpp:17:6: error: no member named 'func' in 'TestClass' tc.func(10, 20); ~~ ^ 

What am I doing wrong?

3 Answers 3

1

Simple syntax subtleties.

func = &TestClass::TestMethod; // ^ Missing ampersand to form a pointer-to-member TestClass tc; (tc.*func)(10, 20); // ^^ Using the dot-star operator to dereference the pointer-to-member, // while minding its awkward precedence with respect to the call operator. 
Sign up to request clarification or add additional context in comments.

2 Comments

Do you know 1. Why I need to take explicitly take the address of the function (I don't need to do this, for normal function pointers)? And 2. Why I need to explicitly dereference the pointer (I neither need to do this, with normal function pointers)?
@Herickson I'm afraid "because the Standard says so" is the answer. There's a fixed syntax for forming pointers-to-members, and it's &A::b (even &(A::b) doesn't cut it). .* is not a dot operator followed by a dereference operator, but a single operator which dereferences pointers-to-members. The dot operator only works with member names on its right-hand side.
1

func = TestClass::TestMethod; should be func = &TestClass::TestMethod;, and tc.func(10, 20) should be (tc.*func)(10, 20) (in the latter, note that there are two changes: . becomes .*, and there are added parentheses; both are needed).

4 Comments

Do you know 1. Why I need to take explicitly take the address of the function (I don't need to do this, for normal function pointers)? And 2. Why I need to explicitly dereference the pointer (I neither need to do this, with normal function pointers)?
@Herickson: The way that regular functions act like pointers to functions, and vice-versa, is inherited from C. Since C doesn't support pointers to members, it wasn't necessary for those to work that way in C++.
@VaughnCato Thank you, so I cannot really compare vanilla function pointers with pointers to member-functions?
@Herickson: No, they are very different.
1

Pointers to members (functions or otherwise), are very different than regular pointers, despite having some similarity in the syntax. The way that regular functions act like pointers to functions, and vice-versa, is inherited from C, but C doesn't support pointers to members, so it wasn't necessary for those to work that way in C++.

To make a pointer to member, you have to explicitly use &, and you have to explicitly use .* to indirect it, which is perhaps more what you might expect if you weren't used to the way functions work in C:

func = &TestClass::TestMethod; (tc.*func)(10, 20); 

Comments