简体   繁体   中英

Passing a (possibly) virtual method as a function pointer in C++

I need to convert this code into a function pointer call for Visual Studio 2008. The GetValue() func could be virtual, but not always, and the GetObject() in different contexts would return different types.

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

The calling function would pass in the GetObject()->GetValue (a pointer to a func + the object instance on which that function should be called), and the parameters will be supplied by the callee function:

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

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

Thanks!

You really want std::tr1::function<int(int int)> for this job. Check it's documentation on MSDN and you shall be a happy man.

Your Foo needs to also take a pointer to an object of class T :

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

If GetObject() can return different types, then you will need to work with templates. Something like this:

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

int Bar() {
    return Foo(GetObject());
}

This is basically, compile time polymorphism

EDIT : If you need to specify which function to call as well, then you can do something like this:

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());
}

EDIT : What this boils down to, is you can write code like this:

#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;
}

types A and B are unrelated, but i can pass a common handler to both. The question is, why is this necessary? Why not just do something like this (avoid the whole mess):

#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;
}

I don't see what you can gain by having the type, the object and the function to call all determined by the template, may as well just do it directly, or maybe with a few simple thin wrappers.

Also, why not just have all of the types that can be returns by GetObject use a common interface that they inherit from, so you can just use virtual functions as they were intended? This has a bit of a "code smell" to it...

Your functions are global, therefore you object may be global, with a wrapper function:

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(...)

Cheers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM