一般来说,函数指针的用法是比较简单的。 比如对于函数:

可以使用:

或者为了复用:

但是当你使用类成员函数指针的时候,会发现完全不是那么一回事!而我今天就杯具的遇上了。。
废话不多说,直接上代码吧

注释的部分千万不要打开,也千万不要以为是一样的,如果你不听我的劝阻非要试一下,好吧,他们会分别报如下错误:

对于原因现在也没时间去钻研了,如果哪位朋友知晓麻烦告知一下,多谢~

暂无相关产品

22则回应给“关于类成员函数指针的正确写法”

  1. narky说道:

    不用想太多
    ->* 就是固定的调用成员函数指针的操作符

    看这里
    http://www.builder.com.cn/2008/0327/785349.shtml

    [回复]

    Dante 回复:

    被系统当作垃圾评论了。。。才看到。。
    这篇文章在CSDN上看到过,呵呵,我也觉得当作固定用法得了,深究太累。。。

    [回复]

  2. narky说道:

    这是一个固定调用法
    看这里
    http://www.builder.com.cn/2008/0327/785349.shtml

    [回复]

  3. Marshall说道:

    我觉得可能因为成员函数有默认this参数的原因吧

    [回复]

    Dante 回复:

    嗯,大体看了一下介绍,好像这种成员函数的函数指针不是4个字节,然后就没有再深究了。。

    [回复]

  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 回复:

    居然被系统当作垃圾评论,看来过滤器有问题。。。
    瑞士菜刀说的很详细,不过还是有一点不太理解,能否解释一下选择成员的意思呢?

    [回复]

  5. 瑞士菜刀说道:

    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 的隐式指针传入。

    [回复]

  6. lichray说道:

    试一下 BSD C 的经典写法就知道错在哪儿了:
    ptrFunc(num);

    error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘ptrFunc (…)’

    [回复]

    Dante 回复:

    ->*居然是个操作符。。。
    C++的语法太复杂了。。

    [回复]

    瑞士菜刀 回复:

    不是的,按照运算符优先级,->比*优先。于是先确定成员归属,之后 * 解析指针的时候由于已经确定了成员归属,可以在解析的时候提供 this 指针,所以成功。

    this->(*p)的做法是先解析指针,后确定归属。解析指针的时候没法提供 this 指针。

    [回复]

    依云 回复:

    呵呵,所以尽管有强大的STL,我还是不喜欢C++。

    [回复]

  7. 瑞士菜刀说道:

    成员函数指针写成 int (Foo::*ptrFunc)(int); 是因为调用 ptrFunc 需要隐式提供一个 Foo *const this 指针。平时调用时由于 . 和 -> 确定了成员函数的归属,于是编译器可以提供这个指针。

    (*ptrFunc)(num); 的做法显然没法提供对象指针,所以是非法调用。

    (this->(*ptrFunc))(num); 由于括号的作用,先解析指针,后确定成员归属。解析指针的时候无法提供对象指针,本质上是和前一种做法一样的。

    (this->*ptrFunc)(num); 由于运算符优先级 -> 大于 * 运算符,先确定成员归属,后解析指针。在解析指针时由于已经确定了归属,可以用 this 当作对象指针隐式传入 ptfFunc,所以调用有效。

    可见 .* 和 ->* 不是操作符。

    [回复]

  8. 瑞士菜刀说道:

    成员函数指针写成 int (Foo::*ptrFunc)(int); 是因为调用 ptrFunc 需要隐式提供一个 Foo *const this 指针。平时调用时由于 . 和 -> 确定了成员函数的归属,于是编译器可以提供这个指针。

    (*ptrFunc)(num); 的做法显然没法提供对象指针,所以是非法调用。

    (this->(*ptrFunc))(num); 由于括号的作用,先解析指针,后确定成员归属。解析指针的时候无法提供对象指针,本质上是和前一种做法一样的。

    (this->*ptrFunc)(num); 由于运算符优先级 -> 大于 * 运算符,先确定成员归属,后解析指针。在解析指针时由于已经确定了归属,可以用 this 当作对象指针隐式传入 ptfFunc,所以调用有效。

    可见 .* 和 ->* 不是操作符。

    [回复]

  9. Terrence说道:

    我的理解是这样的:

    innerFunc是在Foo的域里面的,所以要想调用innerFunc,就要用 作用域::函数名(this->*ptrFunc) 的方法来调用。类似的功能可以通过使用承继类的父类指针来做。

    同理 如果把innerFunc改成static,那么就不需要加域作用空间了。

    [回复]

    Dante 回复:

    对,关于this应该是这样理解~
    只是不明白->*这个操作符是怎么回事,this->*ptrFunc不能写成this->(*ptrFunc)。
    能否指教一下?

    [回复]

    Terrence 回复:

    我认为这里是把编译的一些细节带到了代码编写里面来了。
    函数在编译器中是通过指针来保存的(C和C++最终都变成了汇编),书写代码时不需要考虑这种情况。在函数指针的情况下,
    可以把*ptrFunc当成是innerFunction的代称,调用innerFunction的时候,完整的写法是this->innerFunctino(),也可以直接写innerFunction(编译器给处理了)。所以就有了this->*ptrFunc,同样this->(innerFunction)或this->(*ptrFunc)都是不对的。
    我的理解就是这样子的,再深入的就要找了解编译器结构的人来解释了。

    [回复]

  10. 渡水的疯子说道:

    多谢解释,我也学习了!

    [回复]

  11. sw说道:

    ->*和.*是两个很不常见的C++的操作符…………

    [回复]

    Dante 回复:

    的确很不常见。。。。。

    [回复]

  12. Mr.Bear说道:

    那里写成
    ((*this).*ptrFunc)(num);
    的话,编译也能通过。
    (当然,还没见过这么用this的。。。)

    就如瑞士菜刀说的,这里就是个先解析谁的问题。

    同样的*操作符的情况下,先解析this就没问题;先解析ptrFunc了,就不行了。

    ->优先级比*高还是第一次意识到,向瑞士菜刀学习了!

    [回复]

  13. ultrahabbit说道:

    楼上多位说得不对。

    C++中, ->*与.*都是单独的专门的操作符。这点千真万确,随手看看C++标准或MSDN联机帮助就知道了。

    1. 类成员函数指针与普通函数指针的却别是前者需要一个类实例(即对象)的地址作为隐蔽参数传入函数。这叫做thiscall调用协议,是用ECX寄存器来传递该值的。所以,类成员函数指针的使用就不能用普通函数指针的*(解引用算符)。因此,普通的成员函数在其它成员函数内的调用,既可以写成: _memFunc(); 也可以写成 this->_memFunc(); 但是正如博主的例子那样,类成员函数指针在其它成员函数内的调用不允许写成 (*_memFuncPtr)(); 因为这与普通函数指针的用法混淆了。 C++标准规定这里必须写成(this->*_memFuncPtr)();

    2. 加括号问题。首先,->* 是一个单独的运算符。如果你写成了 ->(* ) 当然编译报错!!! 其次,再查看C++运算符的优先级列表,最高优先级是:: 作用域分辨运算符,第2高优先级是 . -> [] ()函数调用 等二元运算符, 第3高优先级是&取地址 *解引用等单元运算符, 第4高优先级就是 .* ->*这两个特殊运算符。知道了这些,就应该明白博主的例子中,必须写为 (this->*ptrFunc)(num);

    [回复]

发表评论