2010-05-28 5 views
0

J'ai construit plusieurs classes (A, B, C ...) qui effectuent des opérations sur le même BaseClass. Exemple:Comment donner des propriétés à des classes C++ (interfaces)

struct BaseClass { 
    int method1(); 
    int method2(); 
    int method3(); 
} 
struct A { int methodA(BaseClass& bc) { return bc.method1(); } } 
struct B { int methodB(BaseClass& bc) { return bc.method2()+bc.method1(); } } 
struct C { int methodC(BaseClass& bc) { return bc.method3()+bc.method2(); } } 

Mais comme vous pouvez le voir, chaque classe A, B, C ... utilise uniquement un sous-ensemble des méthodes disponibles BaseClass et je voudrais diviser le BaseClass en plusieurs morceaux tels que c'est clair ce qu'il a utilisé et ce qui ne l'est pas. Par exemple, une solution pourrait consister à utiliser l'héritage multiple:

// A uses only method1() 
struct InterfaceA { virtual int method1() = 0; } 
struct A { int methodA(InterfaceA&); } 

// B uses method1() and method2() 
struct InterfaceB { virtual int method1() = 0; virtual int method2() = 0; } 
struct B { int methodB(InterfaceB&); } 

// C uses method2() and method3() 
struct InterfaceC { virtual int method2() = 0; virtual int method3() = 0; } 
struct C { int methodC(InterfaceC&); } 

Le problème est que chaque fois que j'ajouter un nouveau type d'opération, je dois changer la mise en œuvre de BaseClass. Par exemple:

// D uses method1() and method3() 
struct InterfaceD { virtual int method1() = 0; virtual int method3() = 0; } 
struct D { int methodD(InterfaceD&); } 

struct BaseClass : public InterfaceA, public InterfaceB, public InterfaceC 
// here I need to modify the existing code to add class D 
{ ... } 

Savez-vous un moyen propre que je peux faire cela?

Merci pour votre aide

modifier:

j'oublié de mentionner qu'il peut aussi se faire avec des modèles. Mais je n'aime pas cette solution non plus car l'interface requise n'apparaît pas explicitement dans le code. Vous devez essayer de compiler le code pour vérifier que toutes les méthodes requises sont correctement implémentées. De plus, il faudrait instancier différentes versions des classes (une pour chaque paramètre de modèle de type BaseClass) et ce n'est pas toujours possible ni souhaité.

Répondre

0

profil d'emploi Adapter

struct InterfaceA { virtual int method1() = 0; } 

struct A { int methodA(InterfaceA& bc) { return bc.method1(); } } 

struct BaseClassAdapterForA: public InterfaceA 
{ 
    BaseClassAdapterForA(BaseClass& _bc) : bc(_bc) {} 
    virtual int method1() 
    { 
     //note that the name of BaseClass method 
     //can be anything else 
     return bc.method1(); 
     // or return bc.whatever(); 
    } 
private: 
    BaseClass& bc; 
}; 
//usage 
BaseClass bc; 
A a; 
BaseClassAdapterForA bca(bc); 
a.methodA(bca); 
+0

C'est exactement ce dont j'ai besoin! Merci – caas

0

Je ne vois rien de mal avec une classe dérivée qui n'utilise pas certains éléments de sa classe de base.

Une classe dérivée n'est pas, et ne devrait pas être, nécessaire pour utiliser tout à sa disposition.

Par conséquent, je ne vois rien de mal dans votre implémentation d'origine, et pas besoin de le refactoriser.

+0

Salut, merci d'avoir pris le temps de répondre. Le fait est que la classe 'A' n'a besoin que d'une classe qui implémente' InterfaceA'. Faire 'A' dépend de/all/des méthodes de' BaseClass' rend difficile la réutilisation. Par exemple, il serait trop pénible d'exiger 'BaseClass2' pour implémenter toutes les méthodes de' BaseClass' juste parce que je veux pouvoir l'utiliser avec 'A' (et non' B' ou 'C'). Voyez-vous le point? – caas

0

Les appelants de la méthode A, de la méthode B, ... devraient-ils savoir lesquelles des méthodes 1,2,3 sont réellement utilisées?

Si oui, vous pouvez diviser la classe de base en 3 interfaces différentes, et ajouter exactement les arguments d'interface nécessaires par les méthodes 1, 2 et 3, comme ceci:

class Interface1 {virtual int method1() = 0;}; 
class Interface2 {virtual int method2() = 0;}; 
class Interface3 {virtual int method3() = 0;}; 

class A 
    { 
    int methodA(Interface1 &i1) 
     { 
     return i1.method1(); 
     } 
    }; 

class B 
    { 
    int methodB(Interface1 &i1, Interface2 &i2) 
     { 
     return i1.method1() + i2.method2(); 
     } 
    }; 

class C 
    { 
    int methodC(Interface2 &i2, Interface3 &i3) 
     { 
     return i2.method2() + i3.method3(); 
     } 
    }; 

L'appelant peut encore choisir d'hériter de plusieurs interfaces, comme ceci:

class MyClass : public Interface2, public Interface3 
    { 
    int method2() {...} 
    int method3() {...} 
    }; 
... 
MyClass myClass; 
C c; 
c.methodC(myClass,myClass); 
+1

N'oubliez pas que dans C++ 'method1()', 'method2()', et 'method3()' doivent être virtuels, ou le polymorphisme ne fonctionnera pas. –

+1

Selon ce que fera 'BaseClass :: methodN', il n'est pas nécessaire de rendre les méthodes virtuelles. En outre, il existe toujours une possibilité pour les interfaces non virtuelles. (http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface) – ablaeul

+0

@In silico, vous avez raison. J'étais un peu hâtif. Edité pour le corriger à nouveau. – Patrick

Questions connexes