C++类成员函数指针转非静态成员函数

40
class Foo {
public:
    Foo() { do_something = &Foo::func_x; }

    int (Foo::*do_something)(int);   // function pointer to class member function

    void setFunc(bool e) { do_something = e ? &Foo::func_x : &Foo::func_y; }

private:
    int func_x(int m) { return m *= 5; }
    int func_y(int n) { return n *= 6; }
};

int
main()
{
    Foo f;
    f.setFunc(false);
    return (f.*do_something)(5);  // <- Not ok. Compile error.
}

我该如何让这个工作起来?


1
即使没有标记为静态函数,func_xfunc_y不也是静态函数吗? - Sideshow Bob
6个回答

36
 class A{
    public:
        typedef int (A::*method)();

        method p;
        A(){
            p = &A::foo;
            (this->*p)(); // <- trick 1, inner call
        }

        int foo(){
            printf("foo\n");
            return 0;
        }
    };

    void main()
    {
        A a;
        (a.*a.p)(); // <- trick 2, outer call
    }

Tudok,我再次阅读了你的帖子后意识到你也给出了正确的答案(技巧2)。谢谢。 - Girish
你的代码无法运行。我尝试复制/粘贴并尝试编译。test_function_pointer_2.C: 在构造函数 'A::A()' 中: test_function_pointer_2.C:7: 错误:类型为 'int (A::)()' 的参数与 'int (A::*)()' 不匹配。 - user180574
1
@user180574,我记得它确实起作用了。无论如何,你是对的。我用gcc测试了一下,得到了相同的错误。我已经修复了它。 - Nick Dandoulakis

33
您需要的是以下这行代码:

   return (f.*f.do_something)(5);

(那个代码可以编译——我已经尝试过了)

"*f.do_something" 指的是指针本身——"f"告诉我们从哪里获取 do_something 的值。但是当我们调用该函数时,仍然需要提供一个对象作为 this 指针。这就是为什么我们需要 "f." 前缀的原因。


9
技术上说,“f.do_something”返回指针,而“.*”操作符在类上调用指向成员函数的指针。 - Todd Gardner
所以我认为 return (f.*Foo::do_something)(5) 也应该可以工作。 - ThomasMcLeod
1
@ThomasMcLeod 它并不会。 - Joey Dumont
啊,这意味着如果你有 Foo g,那么这也会编译和运行:return (g.*f.do_something)(5); 对吧?(即使没有很好的理由这样做) - Andy
@ThomasMcLeod 不行,因为 Foo::do_something 是类的数据成员名称。你需要一个实例来访问非静态数据成员。 - Caleth
@Caleth,正确。这已经是几年前的事了,但我想我第一次误解了问题。 - ThomasMcLeod

3
class A {
    int var;
    int var2;
public:
    void setVar(int v);
    int getVar();
    void setVar2(int v);
    int getVar2();
    typedef int (A::*_fVar)();
    _fVar fvar;
    void setFvar(_fVar afvar) { fvar = afvar; }
    void insideCall() { (this->*fvar)(); }
};

void A::setVar(int v)
{
    var = v;
}

int A::getVar()
{
    std::cout << "A::getVar() is called. var = " << var << std::endl;
    return var;
}

void A::setVar2(int v2)
{
    var2 = v2;
}

int A::getVar2()
{
    std::cout << "A::getVar2() is called. var2 = " << var2 << std::endl;
    return var2;
}

int main()
{
    A a;
    a.setVar(3);
    a.setVar2(5);

//    a.fvar = &A::getVar;
    a.setFvar(&A::getVar);
    (a.*a.fvar)();

    a.setFvar(&A::getVar2);
    (a.*a.fvar)();

    a.setFvar(&A::getVar);
    a.insideCall();

    a.setFvar(&A::getVar2);
    a.insideCall();

    return 0;
}

我扩展了Nick Dandoulakis的答案,谢谢。
我添加了一个函数,可以从类外设置成员函数指针。我又添加了另一个函数,可以在类外调用成员函数指针的内部调用。

不要只贴一段代码,还请解释为什么这段代码可以解决所提出的问题。没有解释,这不是一个答案。 - Martijn Pieters
@MartijnPieters 我写过,它是从Nick Dandoulakis的答案扩展而来的。那里已经解释了。我在stackoverflow上是新手,也许我需要用不同的方式来表达。 - Volkan Ozyilmaz
好的,你可以解释一下你改了什么,比如为什么改。 - Martijn Pieters

0
#include<iostream>
using namespace std;

class A {

public:
    void hello()
    {
        cout << "hello" << endl;
    };

    int x = 0;

};


void main(void)
{

    //pointer
    A * a = new A;
    void(A::*pfun)() = &A::hello;
    int  A::*v1 = &A::x;

    (a->*pfun)();
    a->*v1 = 100;
    cout << a->*v1 << endl << endl;

    //----------------------------- 
    A  b;
    void(A::*fun)() = &A::hello;
    int  A::*v2 = &A::x;

    (b.*fun)();
    b.*v2 = 200;
    cout << b.*v2 << endl;

}

0
尝试执行 (f.*do_something)(5);

-4

我认为可以使用静态成员函数调用类的非静态成员。


1
这是不可能的。在类声明中修改数据成员时,static关键字指定该成员的一个副本由类的所有实例共享。在类声明中修改成员函数时,static关键字指定该函数仅访问静态成员。请参阅MSDN参考。 - ForceMagic
好的,你可以通过构造函数来保存所有实例的列表,然后对所有实例进行调用,但我觉得这有点奇怪 :p - Willem D'Haeseleer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接