2016-08-26 1 views
2

J'ai un code comme celui-ci (Ceci est juste un extrait, pas complètement code valide):En passant la méthode d'une classe abstraite comme std :: fonction

class AbstractClass { 
public: 
    AbstractClass() {} 
    virtual ~AbstractClass() {} 
    virtual void doA() { std::cout << "doA1\n"; }; 
    virtual void doB() = 0; 
}; 

class ImplClass : public AbstractClass { 
public: 
    ImplClass() {} 
    virtual ~ImplClass() {} 
    virtual void doA() override { std::cout << "doA2\n"; }; 
    virtual void doB() override { std::cout << "doB2\n"; }; 
}; 

Maintenant, je voudrais enregistrer un appel à une méthode de membre du AbstractClass dans un std :: fonction comme ceci:

int main() { 
    AbstractClass* aClass = new ImplClass(); 
    std::function<void()> func = std::bind(&AbstractClass::doA, *aClass) 

    delete aClass; 
    return 0; 
} 

Cependant, cela ne fonctionne pas, selon le compilateur en raison de l'existence de méthodes virtuelles pures dans AbstractClass.

Edit: Pour référence l'erreur complète

In file included from source_file.cpp:2:0: 
/usr/include/c++/5/functional: In instantiation of ‘struct std::_Bind_helper<false, void (AbstractClass::*)(), AbstractClass&>’: 
/usr/include/c++/5/functional:1462:5: required by substitution of ‘template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...) [with _Func = void (AbstractClass::*)(); _BoundArgs = {AbstractClass&}]’ 
source_file.cpp:26:72: required from here 
/usr/include/c++/5/functional:1445:71: error: invalid abstract parameter type ‘AbstractClass’ 
     typedef _Bind<__func_type(typename decay<_BoundArgs>::type...)> type; 
                    ^
source_file.cpp:5:7: note: because the following virtual functions are pure within ‘AbstractClass’: 
class AbstractClass { 
    ^
source_file.cpp:10:18: note: virtual void AbstractClass::doB() 
    virtual void doB() = 0; 
       ^
source_file.cpp: In function ‘int main()’: 
source_file.cpp:26:72: error: no matching function for call to ‘bind(void (AbstractClass::*)(), AbstractClass&)’ 
    std::function<void()> func = std::bind(&AbstractClass::doA, *aClass) 
                     ^
In file included from source_file.cpp:2:0: 
/usr/include/c++/5/functional:1462:5: note: candidate: template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...) 
    bind(_Func&& __f, _BoundArgs&&... __args) 
    ^
/usr/include/c++/5/functional:1462:5: note: substitution of deduced template arguments resulted in errors seen above 
/usr/include/c++/5/functional:1490:5: note: candidate: template<class _Result, class _Func, class ... _BoundArgs> typename std::_Bindres_helper<_Result, _Func, _BoundArgs>::type std::bind(_Func&&, _BoundArgs&& ...) 
    bind(_Func&& __f, _BoundArgs&&... __args) 
    ^
/usr/include/c++/5/functional:1490:5: note: template argument deduction/substitution failed: 
source_file.cpp:26:72: note: couldn't deduce template parameter ‘_Result’ 
    std::function<void()> func = std::bind(&AbstractClass::doA, *aClass) 
                     ^

Y at-il une solution à mon problème? Je n'en ai pas trouvé jusqu'à présent.

+0

Quelle est l'erreur que vous obtenez? – NathanOliver

Répondre

9

Vous code lie l'objet pointé par aClass par valeur. Vous voulez lier par référence:

std::function<void()> func = std::bind(&AbstractClass::doA, std::ref(*aClass)); 

Ou tout simplement lier aClass directement, les pointeurs peuvent être utilisés pour this implicite aussi:

std::function<void()> func = std::bind(&AbstractClass::doA, aClass); 

[Live example]

+0

Merci beaucoup, je savais que c'était quelque chose de très simple – Taredon

2

Le meilleur conseil actuel est de favoriser lambdas sur std::bind, ce qui est considéré comme quelque chose d'un anachronisme dans la norme depuis l'arrivée des lambdas.

lambdas:

  1. sont plus explicites
  2. sont plus efficaces
  3. sont moins confus
  4. ne nécessitent pas des constructions alambiquées comme std::ref et std::cref

exemple:

#include <functional> 
#include <iostream> 

class AbstractClass { 
public: 
    AbstractClass() {} 
    virtual ~AbstractClass() {} 
    virtual void doA() { std::cout << "doA1\n"; }; 
    virtual void doB() = 0; 
}; 

class ImplClass : public AbstractClass { 
public: 
    ImplClass() {} 
    virtual ~ImplClass() {} 
    virtual void doA() override { std::cout << "doA2\n"; }; 
    virtual void doB() override { std::cout << "doB2\n"; }; 
}; 

int main() { 
    AbstractClass* aClass = new ImplClass(); 

    // aClass is a pointer, and a copy of that pointer will be 
    // captured. 
    std::function<void()> func = [aClass]{ aClass->doA(); }; 

    func(); 

    delete aClass; 
    return 0; 
} 
+0

C'est bon à savoir, n'ont pas eu beaucoup à faire avec les fonctions ou lambdas avant. Merci beaucoup. – Taredon