2016-05-24 4 views
4

En C++, puis-je créer une implémentation d'une interface à la volée (qui lie idéalement les variables de portée locale). expliquer mieux, donc je vais poser ce que je voudrais que le code pour ressembler à (environ):Puis-je créer une classe anonyme à la volée (implémentation d'une interface) en C++?

// Given the following: 

class Visitor 
{ 
    virtual void visit(const Data& data) = 0; 
} 

class DataStore 
{ 
    void visitData(Visitor& visitor) { /** Invokes visitor with each item of data. */ } 
} 

// Imagine one would write something like: 

void inSomeFunction(DataStore& store) 
{ 
    std::string myName = "bob"; 

    class MyVisitor: public Visitor 
    { 
    public: 
     MyVisitor(const std::string& p): person(p); 
     virtual void visit(const Data& data) override 
     { 
      std::cout << person << " is visiting " << data << std::endl; 
     } 
    private: 
     std::string person; 
    } 

    MyVisitor myVisitor(myName); 
    store.visitData(myVisitor); 
} 

// Instead of the above, I want to write instead something like: 

void inSomeFunction(DataStore& store) 
{ 
    std::string myName = "bob"; 

    store.visitData(
     class: public MyVisitor 
     { 
      virtual void visit(const Data& data) override 
      { 
       std::cout << myName << " is visiting " << data << std::endl; 
      } 
     } 
    ); 
} 

Je me rends compte que je pose 2 questions ici - pouvez-vous créer une classe de anonymouse comme celui-ci, et pouvez-vous lier des variables de la portée locale (comme je l'ai mentionné myName). Mais j'ai besoin des deux pour que ça soit utile.

Si ce qui précède ne peut pas être fait, ce qui est le plus proche peut arriver à utiliser disons C++ 11 lambdas ou similaire, en termes de concision/manque de passe-partout.

+1

Vous pouvez réaliser ce que vous voulez, mais pas comme vous le souhaitez. J'utiliserais un foncteur pour quelque chose comme ça, ou un visiteur qui prend un pointeur de fonction, alors vous pouvez simplement utiliser un lambda. – csl

+0

Mon seul problème est que la façon dont vous spécifiez la signature de type pour un pointeur de fonction en C++ est horrible. Par exemple. Quelle serait la signature de la méthode visitData si je devais utiliser un pointeur de fonction au lieu d'une interface? – nappyfalcon

+0

A moins qu'il y ait une nouvelle, plus belle façon de spécifier le type d'un paramètre qui prend un pointeur de fonction ...? – nappyfalcon

Répondre

9

Si vous avez d'avoir une interface, vous devez faire ce que Kerrek suggéré.

Mais encore mieux serait de changer l'interface de:

class DataStore 
{ 
    void visitData(Visitor& visitor) { 
     // bunch of calls to visitor.visit(...) ... 
    } 
} 

à:

template <class Visitor> 
    void visitData(Visitor visitor) { 
     // bunch of calls to visitor(...) ... 
    } 

Cela vous permettra d'écrire simplement:

std::string myName = "bob"; 
store.visit([myName](const Data& data) { 
    std::cout << myName << " is visiting " << data << std::endl; 
}); 

qui est beaucoup plus naturel à mon avis. Si l'interface de DataStore est hors de votre contrôle, alors cette réponse est totalement discutable.

+0

Cela semble fantastique ... mais je ne comprends pas comment cela fonctionne. Comment le "[myName] (const Data & data) { std :: cout << myName <<" est en train de visiter "<< data << std :: endl; }" mappage vers le paramètre Visitor dans la méthode visitData? – nappyfalcon

+0

@nappyfalcon - parce que le mécanisme C++ _template_ utilise le typage du canard - dans ce cas le paramètre _template type 'Visitor' est _used_ en appelant' operator() 'sur les instances de celui-ci ... donc _any_ type qui implémente' operator() 'fonctionne - Et cela comprend les lambdas. La clé est que la méthode 'visitData' a été modifiée, par Barry, en une' méthode template'. – davidbak

6

Vous pouvez le faire avec un niveau plus d'indirection:

#include <functional> 
#include <utility> 

class AdHocVisitor : public Visitor 
{ 
public: 
    explicit AdHocVisitor(std::function<void(const Data&)> f) : f_(std::move(f)) {} 
    void visit(const Data& data) override { f_(data); } 
private: 
    std::function<void(const Data&)> f_; 
}; 

Utilisation:

AdHocVisitor v([a, &b, this](const Data&) {}); 
store.visitData(v);