最后更新于 .

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

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

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

Pingbacks

Pingbacks已打开。

Trackbacks

引用地址

评论

  1. narky

    narky on #

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

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

    Reply

    1. Dante

      Dante on #

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

      Reply

  2. narky

    narky on #

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

    Reply

  3. Marshall

    Marshall on #

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

    Reply

    1. Dante

      Dante on #

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

      Reply

  4. 瑞士菜刀

    瑞士菜刀 on #

    int (Foo::*ptrFunc)(int);
    之所以成员函数的指针要这么写,是因为成员函数需要隐式提供指向被调对象的指针(即成员函数内部的 this 指针)。

    foo.innerFunc();
    由「.」操作符指明将 foo 的地址作为 this 指针。

    pFoo-&gt;innerFunc();
    由「-&gt;」操作符指明将 pFoo 作为 this 指针。

    (*ptrFunc)(num);
    无法为 ptrFunc 提供隐式的 this 指针,所以是非法调用。

    (this-&gt;(*ptrFunc))(num);
    由于括号的介入,先解析指针,再选择成员。本质上和前一种情况是一样的。

    (this-&gt;*ptrFunc)(num);
    -&gt; 优先级大于 *,于是先选择成员,再解析指针。由于已经由「-&gt;」操作符指定了成员,所以 ptrFunc 可以被隐式提供一个指针。

    Reply

    1. Dante

      Dante on #

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

      Reply

  5. 瑞士菜刀

    瑞士菜刀 on #

    int (Foo::*ptrFunc)(int);
    成员函数指针之所以一定要加上「Foo::」前缀,是因为 Foo 的非静态成员函数要求调用时隐式传入一个 Foo *const this 指针,用来指明被调对象。

    foo.innerFunc();
    pFoo-&gt;innerFunc();
    一般调用时「.」和「-&gt;」操作符表明用 &amp;foo 和 pFoo 来作为 this 指针传入。

    (*ptrFunc)(num);
    错误在于「*」操作符解析指针时无法提供隐式的 this 指针,于是这是一个无效调用。

    (this-&gt;(*ptrFunc))(num);
    错误在于括号的加入改变了优先级,造成先解析指针,再指定成员归属。本质上和前一种情况时一样的,也是缺少 this 指针的无效调用。

    (this-&gt;*ptrFunc)(num);
    「-&gt;」运算符的优先级大于「*」,所以先指定成员归属,再解析指针。于是在解析指针时可以知道这个指针属于 *this 对象,故将其作为 ptrFunc 的隐式指针传入。

    Reply

  6. lichray

    lichray on #

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

    error: must use '.*' or '-&gt;*' to call pointer-to-member function in 'ptrFunc (...)'

    Reply

    1. Dante

      Dante on #

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

      Reply

      1. 瑞士菜刀

        瑞士菜刀 on #

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

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

        Reply

      2. 依云

        依云 on #

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

        Reply

  7. 瑞士菜刀

    瑞士菜刀 on #

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

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

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

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

    可见 .* 和 -&gt;* 不是操作符。

    Reply

  8. 瑞士菜刀

    瑞士菜刀 on #

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

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

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

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

    可见 .* 和 -&gt;* 不是操作符。

    Reply

  9. Terrence

    Terrence on #

    我的理解是这样的:

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

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

    Reply

    1. Dante

      Dante on #

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

      Reply

      1. Terrence

        Terrence on #

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

        Reply

  10. 渡水的疯子

    渡水的疯子 on #

    多谢解释,我也学习了!

    Reply

  11. sw

    sw on #

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

    Reply

    1. Dante

      Dante on #

      的确很不常见。。。。。

      Reply

  12. Mr.Bear

    Mr.Bear on #

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

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

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

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

    Reply

  13. ultrahabbit

    ultrahabbit on #

    楼上多位说得不对。

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

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

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

    Reply

发表评论