2017-08-14 5 views
4

J'essaie d'appeler une fonction membre, éventuellement avec le pointeur d'objet, sans savoir de quelle classe provient la fonction membre. Est-ce possible?Appel du pointeur de fonction membre C++ sans connaître la classe

Fondamentalement, je veux quelque chose comme ce qui suit pour fonctionner.

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; 
} 
+1

Vous pouvez le faire en enveloppant la fonction membre dans un adaptateur statique: http://ideone.com/I4dH4b. Mais je ne suis pas sûr de savoir comment c'est utile. – melpomene

+0

Que voulez-vous réellement faire? Quelle est la tâche spécifique que vous voulez résoudre? Votre programme ne correspond pas au paradigme C++ – LmTinyToon

+2

Vous pouvez être intéressé par 'std :: function'. –

Répondre

4

Cela ressemble beaucoup à un problème XY. Quoi qu'il en soit, essayons de répondre à votre question telle qu'elle est. Un membre de fonction est lié au type de la classe à laquelle il appartient, sauf s'il s'agit d'un membre statique (ce dernier est traité comme un pointeur de fonction ordinaire et vous n'avez même pas besoin de passer un pointeur sur une instance). l'appeler).
Par conséquent, vous pouvez faire callFunc un modèle de fonction et laissez déduire le type pour vous:

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

Voir vers le haut et en cours d'exécution sur wandbox.

Notez que vous pouvez encourir des erreurs lorsque vous static_cast votre obj si son type original (celui que vous avez effacé pour le mettre dans un void *) n'est pas T.


Voici le code complet, vous pouvez voir sur le lien ci-dessus:

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

Je pensais que je devrais utiliser des modèles en quelque sorte. Bien que ce soit plus simple que de torer tout Foo comme je le pensais. –

+0

Question de suivi. Si j'ai besoin de stocker la fonction dans une variable membre, ai-je besoin de modéliser la classe entière (dans ce cas, Foo). –

+0

@Bennett Bernardoni "Si j'ai besoin de stocker la fonction dans une variable membre"; 'std :: function'. –

1

C'est un problème XY. Utilisez un std::function et/ou un 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; 
} 
0

Bien que je trouve la solution fournie par @skypjack plus élégante, voici une solution que les modèles de la Foo -class (non « seulement » la fonction) dans son ensemble. De ce fait, le type obj est connu dans la classe Foo, ce qui pourrait être un avantage (ou peut ne pas l'être).

En outre, voir également une solution qui stocke le membre avec l'objet associé. Peut-être que c'est utile d'une certaine manière:

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