关于类成员函数指针的正确写法
Published on 十月 9, 2010
一般来说,函数指针的用法是比较简单的。 比如对于函数:
1 | int innerFunc(int num); |
可以使用:
1 2 | int (*ptrFunc)(int); ptrFunc = innerFunc;//或&innerFunc |
或者为了复用:
1 2 3 | typedef int (*FUNC)(int); FUNC ptrFunc; ptrFunc = innerFunc;//或&innerFunc |
但是当你使用类成员函数指针的时候,会发现完全不是那么一回事!而我今天就杯具的遇上了。。
废话不多说,直接上代码吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #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对于原因现在也没时间去钻研了,如果哪位朋友知晓麻烦告知一下,多谢~
原创文章,版权所有。转载请注明:转载自Vimer的程序世界 [ http://www.vimer.cn ]
本文链接地址: http://www.vimer.cn/?p=1668
不用想太多
->* 就是固定的调用成员函数指针的操作符
看这里
http://www.builder.com.cn/2008/0327/785349.shtml
[回复]
Dante 回复:
十月 11th, 2010 at 9:38 上午
被系统当作垃圾评论了。。。才看到。。
这篇文章在CSDN上看到过,呵呵,我也觉得当作固定用法得了,深究太累。。。
[回复]
这是一个固定调用法
看这里
http://www.builder.com.cn/2008/0327/785349.shtml
[回复]
我觉得可能因为成员函数有默认this参数的原因吧
[回复]
Dante 回复:
十月 10th, 2010 at 11:31 上午
嗯,大体看了一下介绍,好像这种成员函数的函数指针不是4个字节,然后就没有再深究了。。
[回复]
int (Foo::*ptrFunc)(int);
之所以成员函数的指针要这么写,是因为成员函数需要隐式提供指向被调对象的指针(即成员函数内部的 this 指针)。
foo.innerFunc();
由「.」操作符指明将 foo 的地址作为 this 指针。
pFoo->innerFunc();
由「->」操作符指明将 pFoo 作为 this 指针。
(*ptrFunc)(num);
无法为 ptrFunc 提供隐式的 this 指针,所以是非法调用。
(this->(*ptrFunc))(num);
由于括号的介入,先解析指针,再选择成员。本质上和前一种情况是一样的。
(this->*ptrFunc)(num);
-> 优先级大于 *,于是先选择成员,再解析指针。由于已经由「->」操作符指定了成员,所以 ptrFunc 可以被隐式提供一个指针。
[回复]
Dante 回复:
十月 11th, 2010 at 9:36 上午
居然被系统当作垃圾评论,看来过滤器有问题。。。
瑞士菜刀说的很详细,不过还是有一点不太理解,能否解释一下选择成员的意思呢?
[回复]
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 的隐式指针传入。
[回复]
试一下 BSD C 的经典写法就知道错在哪儿了:
ptrFunc(num);
error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘ptrFunc (…)’
[回复]
Dante 回复:
十月 10th, 2010 at 2:20 下午
->*居然是个操作符。。。
C++的语法太复杂了。。
[回复]
瑞士菜刀 回复:
十月 10th, 2010 at 5:03 下午
不是的,按照运算符优先级,->比*优先。于是先确定成员归属,之后 * 解析指针的时候由于已经确定了成员归属,可以在解析的时候提供 this 指针,所以成功。
this->(*p)的做法是先解析指针,后确定归属。解析指针的时候没法提供 this 指针。
[回复]
依云 回复:
十月 10th, 2010 at 5:55 下午
呵呵,所以尽管有强大的STL,我还是不喜欢C++。
[回复]
成员函数指针写成 int (Foo::*ptrFunc)(int); 是因为调用 ptrFunc 需要隐式提供一个 Foo *const this 指针。平时调用时由于 . 和 -> 确定了成员函数的归属,于是编译器可以提供这个指针。
(*ptrFunc)(num); 的做法显然没法提供对象指针,所以是非法调用。
(this->(*ptrFunc))(num); 由于括号的作用,先解析指针,后确定成员归属。解析指针的时候无法提供对象指针,本质上是和前一种做法一样的。
(this->*ptrFunc)(num); 由于运算符优先级 -> 大于 * 运算符,先确定成员归属,后解析指针。在解析指针时由于已经确定了归属,可以用 this 当作对象指针隐式传入 ptfFunc,所以调用有效。
可见 .* 和 ->* 不是操作符。
[回复]
成员函数指针写成 int (Foo::*ptrFunc)(int); 是因为调用 ptrFunc 需要隐式提供一个 Foo *const this 指针。平时调用时由于 . 和 -> 确定了成员函数的归属,于是编译器可以提供这个指针。
(*ptrFunc)(num); 的做法显然没法提供对象指针,所以是非法调用。
(this->(*ptrFunc))(num); 由于括号的作用,先解析指针,后确定成员归属。解析指针的时候无法提供对象指针,本质上是和前一种做法一样的。
(this->*ptrFunc)(num); 由于运算符优先级 -> 大于 * 运算符,先确定成员归属,后解析指针。在解析指针时由于已经确定了归属,可以用 this 当作对象指针隐式传入 ptfFunc,所以调用有效。
可见 .* 和 ->* 不是操作符。
[回复]
我的理解是这样的:
innerFunc是在Foo的域里面的,所以要想调用innerFunc,就要用 作用域::函数名(this->*ptrFunc) 的方法来调用。类似的功能可以通过使用承继类的父类指针来做。
同理 如果把innerFunc改成static,那么就不需要加域作用空间了。
[回复]
Dante 回复:
十月 11th, 2010 at 9:24 上午
对,关于this应该是这样理解~
只是不明白->*这个操作符是怎么回事,this->*ptrFunc不能写成this->(*ptrFunc)。
能否指教一下?
[回复]
Terrence 回复:
十月 11th, 2010 at 9:44 上午
我认为这里是把编译的一些细节带到了代码编写里面来了。
函数在编译器中是通过指针来保存的(C和C++最终都变成了汇编),书写代码时不需要考虑这种情况。在函数指针的情况下,
可以把*ptrFunc当成是innerFunction的代称,调用innerFunction的时候,完整的写法是this->innerFunctino(),也可以直接写innerFunction(编译器给处理了)。所以就有了this->*ptrFunc,同样this->(innerFunction)或this->(*ptrFunc)都是不对的。
我的理解就是这样子的,再深入的就要找了解编译器结构的人来解释了。
[回复]
多谢解释,我也学习了!
[回复]
->*和.*是两个很不常见的C++的操作符…………
[回复]
Dante 回复:
十一月 11th, 2010 at 10:48 下午
的确很不常见。。。。。
[回复]
那里写成
((*this).*ptrFunc)(num);
的话,编译也能通过。
(当然,还没见过这么用this的。。。)
就如瑞士菜刀说的,这里就是个先解析谁的问题。
同样的*操作符的情况下,先解析this就没问题;先解析ptrFunc了,就不行了。
->优先级比*高还是第一次意识到,向瑞士菜刀学习了!
[回复]