简体   繁体   English

调用C ++成员函数指针而不知道哪个类

[英]Call C++ member function pointer without knowing which class

I am trying to call a member function, possibly given the object pointer, without knowing what class the member function is from. 我试图调用一个成员函数,可能给出了对象指针,而不知道成员函数来自哪个类。 Is this possible? 这可能吗?

Basically I want something like the following to work. 基本上我想要像以下一样工作。

class Foo{
public:
    Foo(void* object): obj(object) {}

    void callFunc(void (*func)()){
        obj->*func();
    }

private:
    void* obj;
};

class Bar{
public:
    Bar(): foo(this) {}

    void callSomeFunc(){
        callFunc(someFunc);
    }

    void someFunc(){
        cout << "hi\n";
    }

private:
    Foo foo;
};

int main(){
    Bar bar;
    bar.callSomeFunc();
    return 0;
}

It looks a lot like an XY-problem. 它看起来很像XY问题。 Anyway, let's try to reply to your question as it is. 无论如何,让我们试着回答你的问题。

A function member is bound to the type of the class to which it belongs, unless it's a static one (the latter is treated just like a plain function pointer and you don't even have to pass a pointer to an instance to call it). 函数成员绑定到它所属的类的类型,除非它是静态函数(后者被视为普通函数指针,你甚至不必将指针传递给实例来调用它) 。
Therefore you can make callFunc a function template and let it deduce the type for you: 因此,您可以将callFunc作为函数模板,并让它为您推导出类型:

template<typename T>
void callFunc(void (T::*func)()){
    (static_cast<T*>(obj)->*func)();
}

See it up and running on wandbox . wandbox上查看并运行

Note that you can incur in errors when you static_cast your obj if its original type (the one you erased to put it in a void * ) isn't T . 注意,你可以在错误招致当你static_cast你的obj如果原始类型(你擦除把它放在一个void * )不T


Here is the full code you can see at the link above: 以下是您可以在上面链接中看到的完整代码:

#include<iostream>

class Foo{
public:
    Foo(void* object): obj(object) {}

    template<typename T>
    void callFunc(void (T::*func)()){
        (static_cast<T*>(obj)->*func)();
    }

private:
    void* obj;
};

class Bar{
public:
    Bar(): foo(this) {}

    void callSomeFunc(){
        foo.callFunc(&Bar::someFunc);
    }

    void someFunc(){
        std::cout << "hi\n";
    }

private:
    Foo foo;
};

int main(){
    Bar bar;
    bar.callSomeFunc();
    return 0;
}

It's an XY problem. 这是一个XY问题。 Use a std::function and/or a lambda. 使用std::function和/或lambda。

#include <functional>
#include <iostream>

class Foo{
public:
    template<class F>
    void callFunc(F&& f){
        f();
    }
};

class Bar : public Foo{
public:
    Bar(): foo() {}

    void callSomeFunc(){
        this->callFunc([this]{ someFunc(); });
    }

    void someFunc(){
        std::cout << "hi\n";
    }

private:
    Foo foo;
};

int main(){
    Bar bar;
    bar.callSomeFunc();
    return 0;
}

Although I find the solution provided by @skypjack more elegant, here a solution that templates the Foo -class (not "only" the function) as a whole. 虽然我发现@skypjack提供的解决方案更加优雅,但这里有一个解决方案,它模拟了Foo类(不仅仅是“函数”)的整体。 Thereby the type of obj is known throughout the Foo -class, which might be an advantage (or may be not). 从而类型obj在整个已知Foo -class,这可能是一个优点(或者可以是不)。

Further, see also a solution that stores the member together with the associated object. 此外,还可以参见将成员与关联对象一起存储的解决方案。 Maybe it's helpful in some way: 也许它在某些方面很有用:

#include <functional>
#include <iostream>


template<class T>
class Foo {
public:
    Foo(T& obj) : _obj(obj) {}

    void callFuncOnObj(void (T::*func)(void)) {
        auto fn = mem_fn(func);
        fn(_obj);
    }

private:
    T &_obj;
};

class Bar{
public:
    Bar() : d(*this) {}

    void callSomeFunc(){
        d.callFuncOnObj(&Bar::someFunc);
    }

    void someFunc(){
        cout << "hi Bar1\n";
    }

private:
    Foo<Bar> d;
};

class Foo2 {
public:
    Foo2(std::function<void(void)> f) : _f(f) {}

    void callFunction() {
        _f();
    }

private:
    std::function<void(void)> _f;
};

class Bar2{
public:
    Bar2() : d(std::bind(&Bar2::someFunc,this)) {}

    void callSomeFunc(){
        d.callFunction();
    }

    void someFunc(){
        cout << "hi Bar2\n";
    }

private:
    Foo2 d;
};


int main(){

    Bar bar;
    bar.callSomeFunc();

    Bar2 bar2;
    bar2.callSomeFunc();

    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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