0Pricing
C++ Academy · Aula

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

  1. O padrão CRTP
  2. Polimorfismo estático
  3. Mixins com CRTP
  4. Quando usar CRTP
← Voltar para C++ Academy