为啥即使从类内部获取成员函数指针值也需要类名限定?
Posted
技术标签:
【中文标题】为啥即使从类内部获取成员函数指针值也需要类名限定?【英文标题】:Why does taking a member function pointer value requires class name qualification even from inside of the class?为什么即使从类内部获取成员函数指针值也需要类名限定? 【发布时间】:2015-12-26 20:13:16 【问题描述】:当返回一个指向该类成员函数之一中的类的成员函数指针时,我仍然必须指定该类。我不能简单地接受地址。例如this code works fine:
class Foo
public:
void func(int param) cout << param << endl;
void (Foo::*getPointer())(int) return &Foo::func;
;
但如果在getPointer
我尝试简单地做:return &func
我得到这个错误:
prog.cpp:在成员函数'
void (Foo::* Foo::getPointer())(int)
'中: prog.cpp:8:43: 错误:ISO C++ 禁止使用不合格或带括号的非静态成员函数的地址来形成指向成员函数的指针。说“&Foo::func
”[-fpermissive]void (Foo::*getPointer())(int) return &func;
为什么我必须在我所处的上下文中指定类?
【问题讨论】:
啊我误解了你的问题,你问Foo::
在&Foo::func
中的必要性。
@JoachimPileborg 是的,为什么编译器无法解决这个问题让我很生气。我不必指定静态函数、成员变量、调用函数时,甚至获取成员变量的地址;但由于某种原因,如果我想要一个函数的地址,我必须指定。
因为标准是这样说的。如果您认为这不合逻辑,那么您如何看待将double
分配给std::string
变量的能力?
您是否真的尝试将double
分配给std::string
变量?这是合法的......(欢迎来到地狱;-))
请注意,对于数据成员,&my_class::data_m
和&data_m
之间存在差异。对成员函数要求 &my_class::mem_fun
似乎更一致。
【参考方案1】:
指针和指向成员的指针是不同的类型,我们可以从 C++ 标准草案3.9.2
[basic.compound] 部分看到,其中包括指针的复合类型以及指向非静态类的指针成员和备注:
静态类成员是对象或函数,以及指向它们的指针 是指向对象或函数的普通指针
我认为在this quote in an answer from Johannes 中从Annotated C++ Reference Manual(ARM) 中很好地描述了这个问题:
请注意,必须显式使用地址运算符来获取 指向成员的指针;没有隐式转换......如果有, 我们在成员函数的上下文中会有歧义......对于 例如,
void B::f() int B::* p = &B::i; // ok p = B::i; // error: B::i is an int p = &i; // error: '&i'means '&this->i' // which is an 'int*' int *q = &i; // ok q = B::i; // error: 'B::i is an int q = &B::i; // error: '&B::i' is an 'int B::*'
尤其是以下几行:
int B::* p = &B::i; // OK
和:
p = &i; // error: '&i'means '&this->i' which is an 'int*'
演示限定名称和非限定名称之间的区别。
【讨论】:
我想我需要拿一份 ARM 的副本去我的 D&E 旁边,你不能买任何一个的 pdf :-( 我想我结合dyp's comment看你的答案。当我做&B::
时,我得到的是偏移量而不是绝对地址。我想我明白所有方法都是通过偏移量调用的,不是实际地址?
@JonathanMee 是一种可能的实现方式,阅读 Pointers to member functions are very strange animals 应该会有所帮助。【参考方案2】:
(...有一个错误的答案...)
在以下情况下看起来更奇怪:
class Foo
public:
virtual void func(int param) cout << param << endl;
void call(int x) Foo::func(x);
void (Foo::*getPointer())(int) return &Foo::func;
;
class Bar : public Foo
public:
void func(int param) override cout << "Hello world!" << endl;
;
int main()
Foo *a = new Bar();
auto p = a->getPointer();
(a->*p)(4);
a->call(4);
return 0;
输出是
你好世界 4
调用Foo::func
是在Foo
类中调用func
,而调用&Foo::func
是虚拟调用。
【讨论】:
非常感谢。现在一切都说得通了。 这是错误的。非静态成员函数地址不是指针,需要使用this
,因此它不必在编译时解析为“地址”。此外,如果 mp
指向 Foo::func
并且您在 Bar
实例上调用它,则将调用 Bar::func
版本。
@6502 Arg!你正在否定我听到的唯一合理的解释!
它变得不合逻辑以上是关于为啥即使从类内部获取成员函数指针值也需要类名限定?的主要内容,如果未能解决你的问题,请参考以下文章