O padrão CRTP
Padrão de template com recorrência curiosa
O padrão CRTP é uma aula grátis de C++ Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C++ Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C++ Academy inclui 4 aulas no total.
O que é CRTP?
O Padrão de Modelo Recorrente Curiosamente (CRTP) é um padrão idiomático do C++ no qual uma classe Derived herda de uma classe base de modelo instanciada com a própria Derived.
- Forma:
class Derived : public Base<Derived> - A classe base conhece seu tipo derivado em tempo de compilação
template <typename T>
class Base {};
class Derived : public Base<Derived> {};O Mecanismo Principal
Dentro da classe base, você pode aplicar static_cast ao ponteiro this para convertê-lo no tipo derivado. Como o tipo derivado é um parâmetro de modelo, essa conversão ocorre totalmente em tempo de compilação, sem custo em tempo de execução.
#include <iostream>
template <typename T>
class Base {
public:
void interface() {
static_cast<T*>(this)->implementation();
}
};
class Derived : public Base<Derived> {
public:
void implementation() { std::cout << "Derived impl\n"; }
};
int main() {
Derived d;
d.interface();
return 0;
}Por que "Recorrente Curiosamente"?
O nome vem do paradoxo aparente: a classe base faz referência à classe derivada, que ainda não está completamente definida quando o modelo da classe base é escrito.
- Isso funciona porque os modelos só são instanciados quando utilizados
- Quando ocorre a instanciação,
Derivedé um tipo completo
Um Primeiro Uso Real
O CRTP permite que uma classe base forneça funcionalidades reutilizáveis que fazem chamadas de volta para a classe derivada. Aqui, a classe base fornece um print() que delega para o name() da classe derivada.
#include <iostream>
#include <string>
template <typename T>
struct Named {
void print() {
std::cout << static_cast<T*>(this)->name() << "\n";
}
};
struct Cat : Named<Cat> {
std::string name() { return "Cat"; }
};
int main() {
Cat c;
c.print();
return 0;
}Sem Tabelas Virtuais
Ao contrário do polimorfismo em tempo de execução, o CRTP não precisa da palavra-chave virtual nem de um ponteiro para uma tabela virtual em cada objeto. O despacho é resolvido inteiramente em tempo de compilação.
- Objetos menores, sem um vptr oculto
- As chamadas podem ser incorporadas
Contando Instâncias
Uma aplicação clássica do CRTP é um contador de objetos. Cada classe derivada recebe automaticamente seu próprio contador estático.
#include <iostream>
template <typename T>
struct Counter {
static inline int count = 0;
Counter() { ++count; }
~Counter() { --count; }
};
struct Widget : Counter<Widget> {};
int main() {
Widget a, b;
std::cout << Widget::count << "\n";
return 0;
}Cada Derived Obtém Seu Próprio Estado
Como Counter<Widget> e Counter<Gadget> são instanciações distintas de modelos, cada uma tem um count estático independente. Essa separação é impossível com uma única classe base que não seja um modelo.
#include <iostream>
template <typename T>
struct Counter {
static inline int count = 0;
Counter() { ++count; }
};
struct A : Counter<A> {};
struct B : Counter<B> {};
int main() {
A a1, a2;
B b1;
std::cout << A::count << " " << B::count << "\n";
return 0;
}O static_cast é Seguro Aqui
A conversão para baixo dentro da classe base é segura somente se todo objeto do tipo Base<T> for realmente um T. O CRTP garante isso por construção, pois T é a classe que herda.
- Nunca instancie
Base<Wrong>para uma classe não relacionada
Operadores de Comparação com CRTP
Você pode sintetizar um conjunto completo de operadores de comparação a partir de um único operator<, herdando de um auxiliar de comparação.
#include <iostream>
template <typename T>
struct Comparable {
friend bool operator>(const T& a, const T& b) { return b < a; }
friend bool operator==(const T& a, const T& b) { return !(a < b) && !(b < a); }
};
struct Num : Comparable<Num> {
int v;
Num(int x) : v(x) {}
friend bool operator<(const Num& a, const Num& b) { return a.v < b.v; }
};
int main() {
std::cout << (Num(3) > Num(2)) << "\n";
return 0;
}Proteção do Construtor Protegido
Para evitar o uso acidental da classe base, forneça a ela um construtor protected para que apenas as classes derivadas possam criá-la.
#include <iostream>
template <typename T>
class Base {
protected:
Base() = default;
public:
void run() { static_cast<T*>(this)->step(); }
};
class Job : public Base<Job> {
public:
void step() { std::cout << "step\n"; }
};
int main() {
Job j;
j.run();
return 0;
}CRTP em Bibliotecas Padrão
O CRTP aparece em diversas bibliotecas reais de C++.
std::enable_shared_from_this<T>o utiliza- Muitas bibliotecas matemáticas de modelos de expressão (Eigen) dependem dele
- Intervalos e auxiliares de iteradores usam padrões semelhantes
Reconhecer a forma X : Base<X> ajuda você a ler código avançado.
Verificação Rápida
Teste sua compreensão da forma do CRTP.
Recapitulação
Você aprendeu o padrão idiomático CRTP.
Derived : Base<Derived>fornece à classe base seu tipo concreto- Um
static_cast<T*>(this)permite o despacho em tempo de compilação - Sem tabela virtual, com objetos menores e chamadas incorporáveis
- É usado para contadores, componentes de comparação e auxiliares de bibliotecas
Perguntas Frequentes
A aula “O padrão CRTP” é grátis?
Sim — o texto completo de “O padrão CRTP” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C++ Academy, atualize para CoddyKit PRO. O curso de C++ Academy inclui 4 aulas no total.
O que vou aprender em “O padrão CRTP”?
Padrão de template com recorrência curiosa Você pratica C++ Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C++ Academy?
Nenhuma experiência prévia é necessária. C++ Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.
Quanto tempo leva a aula “O padrão CRTP”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C++ Academy?
Sim. Cada aula de C++ Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- O padrão CRTP
- Polimorfismo estático
- Mixins com CRTP
- Quando usar CRTP