一般来说,函数指针的用法是比较简单的。 比如对于函数:
int innerFunc(int num);
可以使用:
int (*ptrFunc)(int);
ptrFunc = innerFunc;//或&innerFunc
或者为了复用:
typedef int (*FUNC)(int);
FUNC ptrFunc;
ptrFunc = innerFunc;//或&innerFunc
但是当你使用类成员函数指针的时候,会发现完全不是那么一回事!而我今天就杯具的遇上了。。
废话不多说,直接上代码吧
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
class Foo
{
public:
string m_str;
Foo()
{
m_str = "";
}
void test(char* str,int num)
{
m_str = str;
int (Foo::*ptrFunc)(int);
ptrFunc = &Foo::innerFunc;
//(*ptrFunc)(num);
//(this->(*ptrFunc))(num);
(this->*ptrFunc)(num);
}
int innerFunc(int num)
{
cout<<num<<endl;
cout<<m_str<<endl;
}
};
int main(int argc, const char *argv[])
{
Foo foo;
foo.test("woo",100);
return 0;
}
注释的部分千万不要打开,也千万不要以为是一样的,如果你不听我的劝阻非要试一下,好吧,他们会分别报如下错误:
error: invalid use of `unary *' on pointer to member
和
error: expected unqualified-id before '(' token
error: invalid use of `unary *' on pointer to member
对于原因现在也没时间去钻研了,如果哪位朋友知晓麻烦告知一下,多谢~
narky on #
不用想太多
->* 就是固定的调用成员函数指针的操作符
看这里
http://www.builder.com.cn/2008/0327/785349.shtml
Reply
Dante on #
被系统当作垃圾评论了。。。才看到。。
这篇文章在CSDN上看到过,呵呵,我也觉得当作固定用法得了,深究太累。。。
Reply
narky on #
这是一个固定调用法
看这里
http://www.builder.com.cn/2008/0327/785349.shtml
Reply
Marshall on #
我觉得可能因为成员函数有默认this参数的原因吧
Reply
Dante on #
嗯,大体看了一下介绍,好像这种成员函数的函数指针不是4个字节,然后就没有再深究了。。
Reply
瑞士菜刀 on #
int (Foo::*ptrFunc)(int);
之所以成员函数的指针要这么写,是因为成员函数需要隐式提供指向被调对象的指针(即成员函数内部的 this 指针)。
foo.innerFunc();
由「.」操作符指明将 foo 的地址作为 this 指针。
pFoo->innerFunc();
由「->」操作符指明将 pFoo 作为 this 指针。
(*ptrFunc)(num);
无法为 ptrFunc 提供隐式的 this 指针,所以是非法调用。
(this->(*ptrFunc))(num);
由于括号的介入,先解析指针,再选择成员。本质上和前一种情况是一样的。
(this->*ptrFunc)(num);
-> 优先级大于 *,于是先选择成员,再解析指针。由于已经由「->」操作符指定了成员,所以 ptrFunc 可以被隐式提供一个指针。
Reply
Dante on #
居然被系统当作垃圾评论,看来过滤器有问题。。。
瑞士菜刀说的很详细,不过还是有一点不太理解,能否解释一下选择成员的意思呢?
Reply
瑞士菜刀 on #
int (Foo::*ptrFunc)(int);
成员函数指针之所以一定要加上「Foo::」前缀,是因为 Foo 的非静态成员函数要求调用时隐式传入一个 Foo *const this 指针,用来指明被调对象。
foo.innerFunc();
pFoo->innerFunc();
一般调用时「.」和「->」操作符表明用 &foo 和 pFoo 来作为 this 指针传入。
(*ptrFunc)(num);
错误在于「*」操作符解析指针时无法提供隐式的 this 指针,于是这是一个无效调用。
(this->(*ptrFunc))(num);
错误在于括号的加入改变了优先级,造成先解析指针,再指定成员归属。本质上和前一种情况时一样的,也是缺少 this 指针的无效调用。
(this->*ptrFunc)(num);
「->」运算符的优先级大于「*」,所以先指定成员归属,再解析指针。于是在解析指针时可以知道这个指针属于 *this 对象,故将其作为 ptrFunc 的隐式指针传入。
Reply
lichray on #
试一下 BSD C 的经典写法就知道错在哪儿了:
ptrFunc(num);
error: must use '.*' or '->*' to call pointer-to-member function in 'ptrFunc (...)'
Reply
Dante on #
->*居然是个操作符。。。
C++的语法太复杂了。。
Reply
瑞士菜刀 on #
不是的,按照运算符优先级,->比*优先。于是先确定成员归属,之后 * 解析指针的时候由于已经确定了成员归属,可以在解析的时候提供 this 指针,所以成功。
this->(*p)的做法是先解析指针,后确定归属。解析指针的时候没法提供 this 指针。
Reply
依云 on #
呵呵,所以尽管有强大的STL,我还是不喜欢C++。
Reply
瑞士菜刀 on #
成员函数指针写成 int (Foo::*ptrFunc)(int); 是因为调用 ptrFunc 需要隐式提供一个 Foo *const this 指针。平时调用时由于 . 和 -> 确定了成员函数的归属,于是编译器可以提供这个指针。
(*ptrFunc)(num); 的做法显然没法提供对象指针,所以是非法调用。
(this->(*ptrFunc))(num); 由于括号的作用,先解析指针,后确定成员归属。解析指针的时候无法提供对象指针,本质上是和前一种做法一样的。
(this->*ptrFunc)(num); 由于运算符优先级 -> 大于 * 运算符,先确定成员归属,后解析指针。在解析指针时由于已经确定了归属,可以用 this 当作对象指针隐式传入 ptfFunc,所以调用有效。
可见 .* 和 ->* 不是操作符。
Reply
瑞士菜刀 on #
成员函数指针写成 int (Foo::*ptrFunc)(int); 是因为调用 ptrFunc 需要隐式提供一个 Foo *const this 指针。平时调用时由于 . 和 -> 确定了成员函数的归属,于是编译器可以提供这个指针。
(*ptrFunc)(num); 的做法显然没法提供对象指针,所以是非法调用。
(this->(*ptrFunc))(num); 由于括号的作用,先解析指针,后确定成员归属。解析指针的时候无法提供对象指针,本质上是和前一种做法一样的。
(this->*ptrFunc)(num); 由于运算符优先级 -> 大于 * 运算符,先确定成员归属,后解析指针。在解析指针时由于已经确定了归属,可以用 this 当作对象指针隐式传入 ptfFunc,所以调用有效。
可见 .* 和 ->* 不是操作符。
Reply
Terrence on #
我的理解是这样的:
innerFunc是在Foo的域里面的,所以要想调用innerFunc,就要用 作用域::函数名(this->*ptrFunc) 的方法来调用。类似的功能可以通过使用承继类的父类指针来做。
同理 如果把innerFunc改成static,那么就不需要加域作用空间了。
Reply
Dante on #
对,关于this应该是这样理解~
只是不明白->*这个操作符是怎么回事,this->*ptrFunc不能写成this->(*ptrFunc)。
能否指教一下?
Reply
Terrence on #
我认为这里是把编译的一些细节带到了代码编写里面来了。
函数在编译器中是通过指针来保存的(C和C++最终都变成了汇编),书写代码时不需要考虑这种情况。在函数指针的情况下,
可以把*ptrFunc当成是innerFunction的代称,调用innerFunction的时候,完整的写法是this->innerFunctino(),也可以直接写innerFunction(编译器给处理了)。所以就有了this->*ptrFunc,同样this->(innerFunction)或this->(*ptrFunc)都是不对的。
我的理解就是这样子的,再深入的就要找了解编译器结构的人来解释了。
Reply
渡水的疯子 on #
多谢解释,我也学习了!
Reply
sw on #
->*和.*是两个很不常见的C++的操作符…………
Reply
Dante on #
的确很不常见。。。。。
Reply
Mr.Bear on #
那里写成
((*this).*ptrFunc)(num);
的话,编译也能通过。
(当然,还没见过这么用this的。。。)
就如瑞士菜刀说的,这里就是个先解析谁的问题。
同样的*操作符的情况下,先解析this就没问题;先解析ptrFunc了,就不行了。
->优先级比*高还是第一次意识到,向瑞士菜刀学习了!
Reply
ultrahabbit on #
楼上多位说得不对。
C++中, ->*与.*都是单独的专门的操作符。这点千真万确,随手看看C++标准或MSDN联机帮助就知道了。
1. 类成员函数指针与普通函数指针的却别是前者需要一个类实例(即对象)的地址作为隐蔽参数传入函数。这叫做thiscall调用协议,是用ECX寄存器来传递该值的。所以,类成员函数指针的使用就不能用普通函数指针的*(解引用算符)。因此,普通的成员函数在其它成员函数内的调用,既可以写成: _memFunc(); 也可以写成 this->_memFunc(); 但是正如博主的例子那样,类成员函数指针在其它成员函数内的调用不允许写成 (*_memFuncPtr)(); 因为这与普通函数指针的用法混淆了。 C++标准规定这里必须写成(this->*_memFuncPtr)();
2. 加括号问题。首先,->* 是一个单独的运算符。如果你写成了 ->(* ) 当然编译报错!!! 其次,再查看C++运算符的优先级列表,最高优先级是:: 作用域分辨运算符,第2高优先级是 . -> [] ()函数调用 等二元运算符, 第3高优先级是&取地址 *解引用等单元运算符, 第4高优先级就是 .* ->*这两个特殊运算符。知道了这些,就应该明白博主的例子中,必须写为 (this->*ptrFunc)(num);
Reply