2009-10-21 7 views
2

J'ai une classe qui utilise un « add-on » modèle pour ajouter des fonctionnalités supplémentaires comme ci-dessous:coincé dans une boucle d'exigence de modèle

template< class T > 
class AddOn_A 
{ 
public: 
    int SomeFuncA() 
    { 
     T* pT = static_cast< T* >(this); 
     return pT->DoSomething() + 1; 
    }; 
}; 

class CMyClass : public AddOn_A<CMyClass> 
{ 
public: 
    int DoSomething() 
    { 
     return 100; 
    }; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    CMyClass A; 
    _ASSERT(A.SomeFuncA() == 101); 

    return 0; 
} 

Maintenant, je voudrais étendre cette telle que CMyClass peut accepter différents add -comme AddOn_B.

template< class T > 
class AddOn_B 
{ 
public: 
    int SomeFuncB() 
    { 
     T* pT = static_cast< T* >(this); 
     return pT->DoSomething() + 2; 
    }; 
}; 

template< class AddOn > 
class CMyClass : public AddOn 
{ 
public: 
    int DoSomething() 
    { 
     return 100; 
    }; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    // error C3203: 'AddOn_A' : unspecialized class template can't be used as a template argument for template parameter 'AddOn', expected a real type 
    // error C2955: 'AddOn_A' : use of class template requires template argument list 
    CMyClass<AddOn_A> A; 
    _ASSERT(A.SomeFuncA() == 101); 

    // same errors here 
    CMyClass<AddOn_B> B; 
    _ASSERT(B.SomeFuncB() == 102); 

    return 0; 
} 

Malheureusement, chaque ADD_ON nécessite CMyClass en tant que paramètre de modèle qui nécessite une ADD_ON, etc ... Je suis dans une boucle d'exigence.

Y at-il un modèle de magie que je peux utiliser pour obtenir la fonctionnalité que je recherche? Y a-t-il une meilleure méthode pour le faire?

Merci, PaulH

+0

C'est faux à tant de niveaux. Le but de C++ est d'ajouter de la clarté et de ne pas obscurcir le code. Static_cast <> est aussi supposé être utilisé pour convertir des objets de types similaires. Lorsque vous commencez à monter et à descendre la hiérarchie des classes, j'utilise dynaic_cast <> –

+0

@Martin: Il a une erreur de syntaxe en faisant une erreur en écrivant le code. Cela ne signifie pas nécessairement que le code sera difficile à lire. En outre, le 'static_cast' est parfaitement raisonnable dans ce cas. Vous savez à l'heure de compilation que cette distribution n'échouera pas. (Une distribution dynamique ne fonctionnerait même pas dynamiquement ici, car aucun polymorphisme n'est impliqué.) – sbi

Répondre

0

Apparemment, vous essayez d'utiliser la célèbre Curiously Recurring Template Pattern.

Je ne suis pas sûr de ce que vous voulez faire exactement, mais vous pourriez vous en sortir avec une autre solution:

Que faire si vous avez utilisé deux classes:

class Base {}; 

class MyClass: public AddOn<Base> {}; 

Vous pouvez également utiliser une base politique approche:

class PolicyA_A {}; 
class PolicyA_B {}; 

class PolicyB_A {}; 
class PolicyB_B {}; 

template <class PolicyA, class PolicyB> 
class MyClass: private PolicyA, private PolicyB {}; 

typdef MyClass<PolicyA_A, PolicyB_A> MyClassAA; 

L'idée est de déléguer une partie du travail aux stratégies pour ajouter de la flexibilité.

Last but not least, vous pouvez utiliser une approche Decorator:

class Base {}; 

template <class T> 
class AddOn_A: public T {}; 

class MyClass: public AddOn_A< AddOn_B<Base> > {}; 

Il vous permet de se débarrasser de l'héritage virtuel en supprimant l'héritage multi et en faisant la hiérarchie linéaire.

+0

Je pense que l'approche du décorateur est parfaite. Merci pour votre aide. – PaulH

2

Si je comprends bien votre question à droite (pas sûr), alors ce que vous avez besoin est un argument de modèle de modèle:

template< template<class> class AddOn > 
class CMyClass : public AddOn< CMyClass<AddOn> > { 
    // ... 
}; 
+0

D'accord, maintenant cette ligne ajoutée échoue avec l'erreur C3203: 'CMyClass': le modèle de classe non spécialisé ne peut pas être utilisé comme argument de modèle pour paramètre de modèle '', attendu un type réel. Il devrait être ": public AddOn >>" – PaulH

+0

@PaulH: Désolé, j'ai effectivement eu une erreur de syntaxe. Cela devrait compiler maintenant. – sbi

0

Pourquoi ne pas simplement utiliser:

CMyClass< AddOn_A<CMyClass> > A; 
_ASSERT(A.SomeFuncA() == 101); 
Questions connexes