Templates parte 3
De ccppbrasil.org
Tabela de conteúdo |
Templates parte 3 - Curiously Recurring Template Pattern
Continuando com o assunto templates (veja Templates parte 1 e Templates parte 2), nesta terceira parte vou descrever a técnica chamada “Curiously Recurring Template Pattern” ou CRTP.
Este nome é empregado quando a classe base deriva de outra classe cujo parâmetro template é a própria classe derivada.
Ou seja:
class derived : public base<derived>
{
..
}
Aplicação:
Em poucas palavras, esta técnica permite que a classe base acesse a classe derivada através de um cast de seu ponteiro.
A maneira mais comum da classe base acessar a classe derivada é através de funções virtuais. Com a CRTP você tem uma alternativa para conseguir um comportamento semelhante sem a necessidade do overhead da vtable.
Para exemplificar, vou começar com uma solução baseada em funções virtuais:
Por exemplo:
class base
{
virtual void do_on_change()
{
/*default code*/
}
public:
void on_change() { do_on_change(); }
};
class derived : public base
{
void do_on_change()
{
/*new code for do_on_change*/
}
};
int main(){
derived d;
base & b = d;
b.on_change();
}
O código acima mostra o comportamento básico das funções virtuais e não requer grandes explicações. Pelo exemplo a função do_on_change implementada na classe derivada é chamada pela classe base.
Prosseguindo, agora um exemplo equivalente utilizando a técnica CRTP.
template<class T>
class base
{
public:
void on_change()
{
T * p = static_cast<T*> this;
p->do_on_change();
}
};
class derived : public base<derived>
{
public:
void do_on_change()
{
...
}
};
int main()
{
derived d;
base<derived> & b = d;
b.do_change();
}
A chamada da função do_on_change() da classe derivada é feita diretamente pelo ponteiro “this” da classe base convertido para classe derivada.
Mas isso não é gambiarra? Não. Apesar de parecer um pouco estranho a validade do cast é garantida justamente pela herança que foi criada.
Uma das vantagens do uso desta técnica sobre a solução com funções virtuais é justamente não precisar do overhead da vtable e das chamadas de funções virtuais.
Outra vantagem é que você pode acessar variáveis e enumerações da classe derivada e não apenas funções como é o caso da solução com funções virtuais.
E o “curious” do nome vem da onde?
Vem do fato da classe precisar dela mesma para existir. Isto só é possível pois os templates só existem após instanciados. (Não confunda instância de template com instância de objeto)
Conclusão
A solução não substitue as funções virtuais de forma alguma, e não é equivalente em todas as situações.
O uso mais geral da técnica depende da criatividade de cada um, mas é alternativa leve e interessante para muitos problemas.
Vários exemplos desta técnica podem ser encontrados na ATL e WTL.
Links:
Uma exemplo de aplicação da técnica
http://www.angelikalanger.com/Articles/Cuj/05.Manipulators/Manipulators.html
Veja também:
Templates parte 1
Templates parte 2
http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern
