指向成员函数的指针不包含实例的信息?



(这是看完这个答案后的问题)

我尝试了以下代码:

#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;
}

结果:

1 1
true
1005
1005 // the same result as above.
2005
2005 // the same result as above.
  1. 看来a1.pa2.p是一样的。在取消引用并通过附加实例名称调用成员函数之前,是否分配成员函数的地址?

  2. 如果是这样,如果它没有关于实例的信息,那么分配&A::f有什么意义?

非静态成员函数有一个"隐藏"的第一个参数,该参数成为函数内的this指针。因此,实例不是函数本身的一部分,而是作为参数传递的。

请注意"隐藏"两边的引号,因为它仅隐藏在函数签名中。当使用其他方式调用 e 成员函数时,它并没有真正隐藏,而是像任何其他参数一样实际传递。例如,如果使用std::bindstd::thread,则非静态成员函数与实例一起调用作为实际参数。

例:

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();
}

std::thread构造函数的三个参数是要运行的函数,以及函数本身的参数。第一个是调用函数的对象,在thread_func内部变得this

似乎 a1.p 和 a2.p 是相同的。在取消引用并通过附加实例名称调用成员函数之前,是否不分配成员函数的地址?

成员函数的地址调用它的实例无关。来自class.mem:

非静态成员函数的类型是普通

函数类型,非静态数据成员的类型是普通对象类型。没有特殊的成员函数类型或数据成员类型。

(强调我的)

出于重载解析的目的,如果成员函数是非常量函数,则非静态成员函数具有类型X&隐式对象参数,如果成员函数是 const 则const X&。这个隐式对象参数基本上是指在其上调用它的对象。


现在来回答你的第二个问题:

如果是这样,如果 &A::f 没有关于实例的信息,那么分配 &A::f 有什么意义?

使用指针标识成员fp。例如,一个类中可以有多个成员函数。喜欢struct A{void f(); void g(int);int (A::*p)(int);};.因此,通过编写a1.p = &A::f,您可以告诉编译器您希望将f的地址分配给a1.p。另请注意,非静态数据成员的类型也是普通对象类型。

取消引用指针p时,将提供有关实例的信息(例如在哪个实例上调用),就像您在(a1.*(a1.p))(5)(a2.*(a1.p))(5)中所做的那样。

最新更新