【问题标题】:Passing a (possibly) virtual method as a function pointer in C++在 C++ 中将(可能)虚方法作为函数指针传递
【发布时间】:2011-06-27 17:41:42
【问题描述】:

我需要将此代码转换为 Visual Studio 2008 的函数指针调用。GetValue() func 可以是虚拟的,但并非总是如此,不同上下文中的 GetObject() 会返回不同的类型。

...
res = GetObject()->GetValue(x, y);
...

调用函数将传入GetObject()->GetValue(指向函数的指针+调用该函数的对象实例),参数将由被调用函数提供:

void Foo(  (int T::func*)(int, int)  )
{
    ...
    res = func(x, y);
    ...
}

void Bar()
{
    Foo( & GetObject()->GetValue );
}

谢谢!

【问题讨论】:

  • 指向成员函数的指针要求您还提供指向要调用其成员的对象的指针!

标签: c++ function-pointers


【解决方案1】:

你真的很想std::tr1::function<int(int int)> 来做这份工作。检查它在 MSDN 上的文档,你会是一个快乐的人。

【讨论】:

    【解决方案2】:

    您的Foo 还需要一个指向T 类对象的指针:

    typedef int (T::MyMemFun*)(int, int);
    void Foo(MyMemFun f, T * t)
    {
        ...
        res = t->*f(x, y);
        ...
    }
    

    【讨论】:

    • 但是 T 总是不同的——所以它应该是一个模板。
    • @Yuri:你可以随心所欲地模板化,我只是给了你通过指针调用静态成员函数的基本结构。如果您需要更明确的示例,请告诉我。
    【解决方案3】:

    如果GetObject() 可以返回不同的类型,那么您将需要使用模板。像这样的:

    template <class T>
    int Foo(const T &o) {
        return o->GetValue(x, y);
    }
    
    int Bar() {
        return Foo(GetObject());
    }
    

    这基本上是,编译时多态

    编辑: 如果您还需要指定要调用的函数,则可以执行以下操作:

    template <class T, int (T::*F)(int,int)>
    int Foo(const T &o) {
        return (o->*F)(x, y);
    }
    
    int Bar() {
        // there is probably some template magic you can do to avoid knowing "Type" here..
        return Foo<Type, &Type::GetValue>(GetObject());
    }
    

    编辑: 这归结为,您可以编写如下代码:

    #include <iostream>
    
    struct A {
        int GetValue(int x, int y) {
            return 42;
        }
    };
    
    struct B {
        int GetValue(int x, int y) {
            return 123;
        }
    };
    
    template <class T, int (T::*F)(int,int)>
    int Foo(T &o) {
        return (o.*F)(0, 1);
    }
    
    int main() {
        A a;
        B b;
        std::cout << Foo<A, &A::GetValue>(a) << std::endl;
        std::cout << Foo<B, &B::GetValue>(b) << std::endl;
    }
    

    类型 AB 是不相关的,但我可以将一个通用处理程序传递给两者。问题是,为什么这是必要的?为什么不做这样的事情(避免整个混乱):

    #include <iostream>
    
    struct A {
        int GetValue(int x, int y) {
            return 42;
        }
    };
    
    struct B {
        int GetValue(int x, int y) {
            return 123;
        }
    };
    
    int Foo(int x) {
        return x
    }
    
    int main() {
        A a;
        B b;
        std::cout << Foo(a.GetValue()) << std::endl;
        std::cout << Foo(b.GetValue()) << std::endl;
    }
    

    我看不出将类型、对象和要调用的函数全部由模板确定可以得到什么,也可以直接执行,或者使用一些简单的薄包装器。

    另外,为什么不让GetObject 返回的所有类型都使用它们继承自的公共接口,这样您就可以按预期使用虚函数?这有点“代码味道”...

    【讨论】:

    • 不幸的是,“GetValue()”每次也不一样——可能是 GetX 或 GetBlah。
    【解决方案4】:

    你的函数是全局的,因此你的对象可能是全局的,带有一个包装函数:

    public class MyMsgObject
    {
        void ShowMsg(char[] Msg);
    
        // other methods
    };
    
    // ...
    
    // this function belongs to a class, is a method
    void MyMsgObject::ShowMsg(char[] Msg)
    {
        cout << "Method: " << Msg <<"\n";
    }
    
    // this method doesn't belong to any class,
    // its global
    void GlobalShowMsg(char[] Msg)
    {
        cout << "Global: " << Msg <<"\n";
    }
    
    // global var obj, before method wrapper:
    MyMsgObject myGlobalObject;
    
    void MethodWrapperShowMsg(char[] Msg)
    {
        // method pointer is global,
        // your objects must be used as globals:
        myGlobalObject.ShowMsg(Msg);
    }
    
    // declare function pointer ("functor"),
    // syntax is weird
    
    typedef
        void (*MyGlobalFunctorType) (char[] Msg);
    
    void main()
    {
        // declare function pointer variable
        MyGlobalFunctorType MyGlobalFunctorVar = null;
    
        // test function pointer variable with global function
        MyGlobalFunctorVar = &GlobalShowMsg;
        MyGlobalFunctorVar("Hello Earth");
    
        // instantiate class into an object variable
        myGlobalObject = new MyMsgObject();
    
        // test function pointer variable with wrapper function
        MyGlobalFunctorVar = &MethodWrapperShowMsg;
        MyGlobalFunctorVar("Hello Moon");
    } // void main(...)
    

    干杯。

    【讨论】:

      猜你喜欢
      • 2017-11-26
      • 1970-01-01
      • 2012-10-22
      • 2021-10-05
      • 2013-02-15
      • 1970-01-01
      • 2022-08-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多