2010-10-27 5 views
2

Je voulais pouvoir avoir quelque chose comme la sémantique d'interface de Java avec C++. Au début, j'avais utilisé boost::signal pour rappeler des fonctions membres explicitement enregistrées pour un événement donné. Cela a très bien fonctionné. Mais alors j'ai décidé que certains groupes de rappels de fonctions étaient liés et qu'il était logique de les résumer et de les enregistrer pour toutes les fonctions de rappel associées d'une instance en même temps. Mais ce que j'ai appris, c'est que la nature spécifique de boost::bind et/ou prendre la valeur de this semblait faire cette pause. Ou peut-être que c'était juste le fait que la déclaration de la méthode add_listener(X &x) a changé le code généré par boost::bind. Je comprends très mal pourquoi le problème est survenu et je pense qu'il fonctionne probablement correctement selon sa conception. Je suis curieux: ce que devrait j'ai fait à la place? Il y a sûrement une bonne façon de le faire."Interface" comme sémantique avec boost :: bind

Voici quelques exemples de code:

#include <boost/bind.hpp> 
#include <boost/function.hpp> 
#include <iostream> 

using namespace std; 

struct X; 
struct Callback 
{ 
    virtual void add_listener(X &x) = 0; 
}; 

struct X 
{ 
    X() {} 
    X(Callback &c) { c.add_listener(*this); } 
    virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; } 
}; 

struct CallbackReal : public Callback 
{ 
    virtual void add_listener(X &x) 
    { 
     f = boost::bind<void>(boost::mem_fn(&X::go), x); 
    } 

    void go() { f(); } 

    boost::function<void (void)> f; 
}; 


struct Y : public X 
{ 
    Y() {} 

    Y(Callback &c) { c.add_listener(*this); } 
    virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; } 
}; 


int main(void) 
{ 
    CallbackReal c_x; 
    CallbackReal c_y; 

    X x(c_x); 
    Y y(c_y); 

    cout << "Should be 'X'" << endl; 
    boost::bind<void>(boost::mem_fn(&X::go), x)(); 

    cout << "Should be 'Y'" << endl; 
    boost::bind<void>(boost::mem_fn(&X::go), y)(); 

    cout << "------------------" << endl; 

    cout << "Should be 'X'" << endl; 
    c_x.go(); 
    cout << "I wish it were 'Y'" << endl; 
    c_y.go(); 

    return 0; 
} 

D'accord, je ne l'ai pas décrire complètement le problème. Le titre est trompeur.

Oh, mec. Downvote celui-ci. Je n'ai évidemment pas bien décrit le problème et je pense que cela se résume finalement à une erreur syntaxique. :(

+0

Quelle est la sortie? Des erreurs/avertissements du compilateur? –

+1

Je suis confus quant à ce que la «sémantique de l'interface» a à voir avec ce que vous faites ici. Pourquoi n'utilisez-vous pas simplement des classes de base abstraites et des fonctions virtuelles? Voir: http://www.parashift.com/c++-faq-lite/abcs.html#faq-22.4 –

+0

D'accord, il est clair pour moi maintenant que j'ai confondu quelques choses et donné des détails insuffisants dans mon exemple. Ce que je fais * vraiment *, c'est d'utiliser 'boost :: signal' pour appeler les différents gestionnaires enregistrés. Pour utiliser un exemple légèrement plus explicite, disons que j'ai une classe abstraite 'EventListener' avec les méthodes' handleFooEvent', 'handleBarEvent' et' handleBazEvent'. Je voudrais enregistrer une instance d'un 'EventListener' et connecter les méthodes' handle * Event' avec un emplacement correspondant. –

Répondre

3

boost::bind prend ses paramètres en termes de valeur et les copie. Cela signifie

f = boost::bind<void>(boost::mem_fn(&X::go), x); 

passeront une copie de x, qui tranche de la pièce Y de celui-ci (si elle était vraiment un . Y pour commencer) pour obtenir l'envoi virtuel au travail, vous devez passer un pointeur vers boost::bind:

f = boost::bind(&X::go, &x); 

(Notez e vous n'avez pas réellement besoin de mem_fn, ou d'écrire explicitement <void>, puisque boost::bind et la déduction des arguments prennent soin de ceux qui vous conviennent.)

0

Les interfaces Java n'existent pas spécifiquement dans C++. Le plus proche que vous pouvez obtenir est des classes de base abstraites. C'est généralement assez proche.

Le reste de votre question n'a aucun rapport avec les interfaces. Java utilise le modèle Observer pour la connexion et la répartition des événements. La partie de l'interface n'est que légèrement liée car les observateurs sont tenus d'obéir à des interfaces spécifiques (bien sûr, sinon vous n'auriez aucune idée de ce qu'il faut appeler). L'utilisation de boost :: bind pour créer des foncteurs est en fait une abstraction au-delà des interfaces et est donc une solution plus générique. Le modèle d'observateur et les foncteurs sont regroupés dans des idiomes/modèles de signaux/fentes implémentés dans diverses bibliothèques comme boost :: signals, boost :: signals2 et gtk ++. La version Qt est assez différente en mécanique mais similaire dans le concept. Alors, qu'est-ce que cela signifie pour vous aider à comprendre quoi, pourquoi et où? Je suggère de commencer par une recherche sur ce qu'est le pattern Observer et d'essayer d'écrire quelques implémentations.

Questions connexes