2016-04-15 2 views
4

J'ai une telle hiérarchie de classes:Puis-je utiliser CRTP avec plusieurs classes dérivées et les utiliser de façon polymorphique?

template <class Type> 
class CrtpBase 
{ 
protected: 
    Type& real_this() 
    { 
     return static_cast<Type&>(*this); 
    } 
}; 

template <class ChildType> 
class Base : CrtpBase<ChildType> 
{ 
public: 
    void foo() 
    { 
     this->real_this().boo(); 
    } 
}; 

class Derived1 : public Base<Derived1> 
{ 
public: 
    void boo { ... } 
}; 

class Derived2 : public Base<Derived2> 
{ 
public: 
    void boo { ... } 
}; 

La chose est, je veux utiliser mes cours ainsi:

std::vector<Base*> base_vec; 
base_vec.push_bach(new Derived1()); 
base_vec.push_bach(new Derived2()); 
......... 
base_vec[0]->foo(); 

Mais ce n'est pas possible, parce que la classe de base pour tous les dérivés classes est différent (en fait, Base n'est pas du tout un type, c'est un template). Donc, est-il possible d'utiliser crtp avec plusieurs classes dérivées, avec le polymorphisme?

Répondre

3

En effet, il est, vous devez ajouter le non-modèle classe trop de base appropriée:

class AbstractBase 
{ 
public: 
    virtual ~AbstractBase() {} 

    virtual void foo() = 0; 
}; 


template <class ChildType> 
class Base : CrtpBase<ChildType>, public AbstactBase 
{ 
    void foo() override { this->real_this().boo(); } 
}; 

Ensuite, déclarez votre vecteur std::vector<AbstractBase*>. Cela introduit en effet la surcharge de dispatch dynamique (que vous essayiez probablement d'éviter en utilisant CRTP), mais la répartition dynamique est le seul moyen d'obtenir le polymorphisme d'exécution en C++.

Cela peut quand même être bénéfique. Par exemple, si l'implémentation de foo est partagée par toutes les classes dérivées, mais fait appel à de nombreuses fonctions de type boo (chaque classe dérivée ayant une implémentation différente de celles-ci), vous ne paierez le coût de répartition dynamique qu'une seule fois en appelant foo , puis tous les appels effectués au sein defoo sont envoyés statiquement, style CRTP.

D'autre part, si elle est juste un appel à une fonction au sein boo -comme foo, vous pouvez aussi bien faire dans la base virtuelle boo, mettre foo non virtuelle, ainsi se débarrasser de CRTP. Le coût sera le même alors: un envoi non virtuel (foo) et un envoi virtuel (boo).


Side note, vous devriez fortement envisager de stocker des pointeurs intelligents dans le std::vector; possédant les pointeurs bruts sont une mauvaise pratique.

+0

La chose que j'ai utilisée crtp, était d'éviter les fonctions virtuelles, alors quelle est la signification de cette solution? Introduire la classe crtp pour éviter les fonctions virtuelles, puis utiliser la classe abstraite avec fonction virtuelle pour résoudre le problème? non-sens – user1289

+1

@ user1289 Eh bien, CRTP est une solution de compilation, ce qui signifie que vous disposez d'une répartition à la compilation basée sur différents types. Ensuite, vous avez demandé à avoir le même type, ce qui signifie la répartition de l'exécution et donc les fonctions virtuelles. Notez que 'boo()' est toujours envoyé statiquement. – Angew

+0

@ Angew, sans crtp aussi il y aurait seulement besoin d'une expédition d'exécution, dans ce cas, j'ai un temps d'exécution et un statique, probablement pire que sans utiliser crtp. Probablement il n'y a pas de solution à ma question, je voulais juste vérifier s'il y a un hack à cela. – user1289