Quelqu'un peut-veuillez fournir une bonne explication pour CRTP
avec un exemple de code?
S'il vous plaît ne me demandez pas à consulter un livre, je l'ai déjà fais avoir les livres et de les renvoyer, mais j'ai l'habitude de trouver les explications/exemples que vous les gars à venir avec à beaucoup plus convenable et plus pratique dans la compréhension du concept et de beaucoup d'autres choses subtiles qui vont avec un concept.
Réponses
Trop de publicités?En bref, les PFI, c'est quand une classe a une classe de base qui est un modèle de la spécialisation de la classe elle-même. E. g.
template <class T> class X{...};
class A : public X<A> {...};
Il est curieusement récurrents, n'est-ce pas? :)
Maintenant, qu'est-ce vous donner? Cela donne effectivement le X modèle de la capacité d'être une classe de base pour ses spécialisations.
Par exemple, vous pourriez faire un générique de la classe singleton (version simplifiée) comme ceci
template <class ActualClass>
class Singleton
{
public:
static ActualClass& GetInstance()
{
if(p == 0)
p = new ActualClass;
return *p;
}
protected:
static Actualclass* p;
private:
Singleton(){}
Singleton(Singleton const &);
Singleton& operator = (Singleton const &);
};
template <class T>
T* Singleton<T>::p = 0;
Maintenant, pour faire un arbitraire de la classe A un singleton, vous devriez le faire
class A: public Singleton<A>
{
//Rest of functionality
};
Donc, vous voyez? Le singleton modèle suppose que sa spécialisation pour tout type de X seront héritées de singleton<X>
et donc aura toute sa(public, protected) les membres accessibles, y compris l' GetInstance
! Il y a d'autres utilisations de la PFI. Par exemple, si vous voulez compter toutes les instances qui existent actuellement pour votre classe, mais qui veulent saisir cette logique dans un autre modèle (l'idée d'un béton de classe est assez simple, avoir une variable statique, augmentation de l'ctors, diminution de dtors). Essayer de le faire comme un exercice de!
Encore un autre exemple utile, pour boost(je ne suis pas sûr de savoir comment ils ont mis en œuvre, mais PFI va faire trop). Imaginez que vous souhaitez fournir uniquement l'opérateur < pour vos classes, mais automatiquement l'opérateur == pour eux!!!
vous pourriez faire comme ceci:
template<class Derived>
class Equality
{
};
template <class Derived>
bool operator == (Equality<Derived> const& op1, Equality<Derived> const & op2)
{
Derived const& d1 = static_cast<Derived const&>(op1);//you assume this works
//because you know that the dynamic type will actually be your template parameter.
//wonderful, isnit it?
Derived const& d2 = static_cast<Derived const&>(op2);
return !(d1 < d2) && !(d2 < d1);//assuming derived has operator <
}
Maintenant, vous pouvez l'utiliser comme ceci
struct Apple:public Equality<Apple>
{
int size;
};
bool operator < (Apple const & a1, Apple const& a2)
{
return a1.size < a2.size;
}
maintenant, vous n'avez pas prévu explicitement l'opérateur == pour apple? Mais vous l'avez! Vous pouvez écrire
int main()
{
Apple a1;
Apple a2;
a1.size = 10;
a2.size = 10;
if(a1 == a2) //the compiler won't complain!
{
}
}
Cela pourrait sembler que vous écrivez moins si vous venez de l'opérateur == pour Apple, mais imaginer que l'Égalité modèle permettrait de fournir non seulement == mais,>, >=, <=, etc. Et vous pouvez utiliser ces définitions pour plusieurs classes, la réutilisation de code!
PFI est une chose merveilleuse :) HTH
Juste comme remarque:
PFI pourrait être utilisé pour mettre en œuvre polymorphisme statique(qui, comme polymorphisme dynamique mais sans virtuel tableau de pointeur de fonction).
#pragma once
#include <iostream>
template <typename T>
class Base
{
public:
void method() {
static_cast<T*>(this)->method();
}
};
class Derived1 : public Base<Derived1>
{
public:
void method() {
std::cout << "Derived1 method" << std::endl;
}
};
class Derived2 : public Base<Derived2>
{
public:
void method() {
std::cout << "Derived2 method" << std::endl;
}
};
#include "crtp.h"
int main()
{
Derived1 d1;
Derived2 d2;
d1.method();
d2.method();
return 0;
}
La sortie serait :
Derived1 method
Derived2 method