(This is a question after reading this answer)
I tried this code:
#include <iostream>
class A {
public:
int a;
A(int val) : a{val}{}
int f(int);
int (A::*p)(int);
};
int A::f(int in) {
return in + a;
}
int main() {
A a1(1000);
A a2(2000);
// Without these two lines, segmentation fault.
a1.p = &A::f; // no instance information.
a2.p = &A::f; // no instance information.
std::cout << a1.p << " " << a2.p << '\n';
std::cout << std::boolalpha << (a1.p == a2.p) << '\n';
std::cout << (a1.*(a1.p))(5) << '\n';
std::cout << (a1.*(a2.p))(5) << '\n';
std::cout << (a2.*(a1.p))(5) << '\n';
std::cout << (a2.*(a2.p))(5) << std::endl;
}
Results:
1 1
true
1005
1005 // the same result as above.
2005
2005 // the same result as above.
It seems that a1.p
and a2.p
are the same. Is the member function's address not assigned until it is dereferenced and called by attaching the instance's name?
If so, what's the point of assigning &A::f
, if it has no information about the instance?
Non-static member functions have a "hidden" first argument that becomes the this
pointer inside the function. So instance is not part of the function itself, but rather passed as an argument.
Note the quotes around "hidden", because it's only hidden in the function signature. When using other ways to call e member function, it's not really hidden but actually passed like any other argument. For example if using std::bind
or std::thread
, non-static member function are called with the instance as an actual argument.
Example:
struct thread_class
{
int value_;
explicit thread_class(int value)
: value_{ value }
{
}
void thread_func(int arg)
{
std::cout << "arg is " << arg << '\n';
std::cout << "value is " << value_ << '\n';
}
};
int main()
{
thread_class foo;
std::thread thread(&thread_class::thread_func, &foo, 123);
thread.join();
}
The three arguments to the std::thread
constructor is the function to run, and the arguments to the function itself. The first is the object to call the function on, what becomes this
inside thread_func
.