2016-01-31 3 views
0

En Objective C, le langage a intégré la prise en charge de la délégation de classes à d'autres classes. C++ n'a pas cette fonctionnalité (une classe en tant que délégué d'une autre classe) en tant que partie du langage. Une façon d'imiter qui est de séparer la déclaration et la mise en œuvre de cette façon:Comment implémenter "délégation" pour les classes efficacement en C++?

Dans le fichier d'en-tête ah:

class AImpl; 

class A 
{ 
public: 
    A(); 

    void f1(); 
    int f2(int a, int b); 
    // A's other methods... 
private: 
    AImpl *mImpl; 
}; 

Dans le Cpp (fichier de mise en œuvre):

#include "a.h" 

class AImpl 
{ 
public: 
    AImpl(); 
    // repeating the same method declarations from A 
    void f1(); 
    int f2(int a, int b); 
    // AImpl's other methods 
}; 

AImpl::AImpl() 
{ 
} 

void AImpl:f1() 
{ 
    // actual implemetation 
} 

int AImpl::f2(int a, int b) 
{ 
    // actual implmentation 
} 

// AImpl's other methods implementation 

A::A() 
{ 
    mImpl = new AImpl(); 
} 

// A's "forwarder" 

void A::f1() 
{ 
    mImpl->f1(); 
} 

int A::f2(int a, int b) 
{ 
    return mImpl->f2(a, b); 
} 

// etc. 

Cela nécessite de créer manuellement toutes les fonctions "redirecteur" de la classe qui délégueraient à une autre classe pour effectuer le travail en cours. Tardif, c'est le moins qu'on puisse dire.

La question est: existe-t-il un mieux ou un moyen plus productif pour réaliser cet effet en utilisant des modèles ou d'autres constructions de langage C++?

+0

Au lieu de tout cela forwarding vous pouvez simplement déclarer une interface pure dans l'en-tête, ainsi que la déclaration d'une fonction d'usine. Dans le fichier d'implémentation une classe implémentant l'interface, et implémentation de l'usine. En supposant que ce n'est pas l'intention que le code client devrait être capable d'étendre la classe de façon significative. –

+0

Je ne pense pas qu'il y en ait mais j'attendrai quelqu'un plus compétent que moi pour me corriger. –

+1

J'étais sur le point d'écrire une liste complète sur la façon de déléguer la fonction en C++, mais j'ai trouvé que quelqu'un l'avait déjà fait: http://stackoverflow.com/questions/9568150/what-is-ac-delegate vote pour fermer en double –

Répondre

-1

Vous pouvez implémenter une interface virtuelle dans la classe de base.
Toutefois, si vous voulez vraiment déléguer, vous pouvez surcharger le operator-> pour déléguer tous les appels.
Vous n'aurez plus besoin les méthodes d'expédition:

#include <iostream> 
#include <string> 

using namespace std; 

class AImpl; 

class A 
{ 
    public: 
     A(); 

     //Overloading operator -> delegates the calls to AImpl class 
     AImpl* operator->() const { return mImpl; } 

    private: 
     AImpl *mImpl; 
}; 

class AImpl 
{ 
    public: 
     void f1() { std::cout << "Called f1()\n"; } 
     void f2() { std::cout << "Called f2()\n"; } 
}; 

A::A() 
{ 
    mImpl = new AImpl(); 
} 

int main() 
{ 
    A a; 
    a->f1(); //use a as if its a pointer, and call functions of A 

    A* a1 = new A(); 
    (*a1)->f2(); 
} 
+0

Pour être honnête, utiliser 'a' _si c'est un pointeur_ quand ce n'est pas le cas est un peu contre-intuitif et je suppose que cela n'aidera pas le lecteur/mainteneur du code. Mes deux centimes. – skypjack

0

Oui, il est possible. L'un des exemples possibles est:

struct WidgetDelegate 
{ 
    virtual ~WidgetDelegate() {} 
    virtual void onNameChange(std::string newname, std::string oldname) {} 
}; 

class Widget 
{ 
public: 
    std::shared_ptr<WidgetDelegate> delegate; 
    explicit Widget(std::string name) : m_name(name){} 
    void setName(std::string name) { 
     if (delegate) delegate->onNameChange(name, m_name); 
     m_name = name; 
    } 
private: 
    std::string m_name; 
}; 

Utilisation:

class MyWidgetDelegate : public WidgetDelegate 
{ 
public: 
    virtual void onNameChange(std::string newname, std::string oldname) { 
     std::cout << "Widget old name: " << oldname << " and new name: " << newname << std::endl; 
    } 
}; 

int main() 
{ 
    Widget my_widget("Button"); 
    my_widget.delegate = std::make_shared<MyWidgetDelegate>(); 
    my_widget.setName("DoSomeThing"); 
    return 0; 
} 

requis comprend sont:

#include <string> 
#include <iostream> 
#include <memory>