C++ Academy · Les

Het CRTP-idioom

Curiously recurring template pattern

Les 1 van 413 stappen

Het CRTP-idioom is een gratis C++ Academy-les op CoddyKit. Dit is les 1 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject C++ Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus C++ Academy bevat in totaal 4 lessen.

Wat is CRTP?

Het Curiously Recurring Template Pattern (CRTP) is een C++-idioom waarbij een klasse Derived overerft van een basistemplate dat met Derived zelf is geïnstantieerd.

  • Vorm: class Derived : public Base<Derived>
  • De basisklasse leert het afgeleide type tijdens het compileren kennen
template <typename T>
class Base {};

class Derived : public Base<Derived> {};

Het kernmechanisme

Binnen de basisklasse kun je de this-pointer met static_cast omzetten naar het afgeleide type. Omdat het afgeleide type een templateparameter is, is dit volledig een cast tijdens het compileren, zonder uitvoeringskosten.

#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;
}

Waarom "Curiously Recurring"?

De naam komt voort uit de schijnbare paradox: de basisklasse verwijst naar de afgeleide klasse, die nog niet volledig is gedefinieerd wanneer het basistemplate wordt geschreven.

  • Het werkt omdat templates alleen worden geïnstantieerd wanneer ze worden gebruikt
  • Op het moment van instantiatie is Derived een compleet type

Een eerste echte toepassing

Met CRTP kan een basisklasse herbruikbare functionaliteit leveren die terugroept naar de afgeleide klasse. Hier levert de basisklasse een print() die het werk delegeert aan name() van de afgeleide klasse.

#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;
}

Geen virtuele tabellen

In tegenstelling tot polymorfisme tijdens runtime heeft CRTP geen sleutelwoord virtual en geen vtable-pointer in elk object nodig. De dispatch wordt volledig tijdens het compileren opgelost.

  • Kleinere objecten (geen verborgen vptr)
  • Aanroepen kunnen worden geïnlineerd

Instanties tellen

Een klassieke toepassing van CRTP is een objectteller. Elke afgeleide klasse krijgt automatisch een eigen statische teller.

#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;
}

Elke afgeleide klasse krijgt een eigen toestand

Omdat Counter<Widget> en Counter<Gadget> verschillende template-instanties zijn, heeft elk ervan een onafhankelijke statische count. Deze scheiding is onmogelijk met één niet-templatebasisklasse.

#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;
}

De static_cast is hier veilig

De downcast binnen de basisklasse is alleen veilig als elk object van het type Base<T> daadwerkelijk een T is. CRTP garandeert dit per constructie, omdat T de klasse is die overerft.

  • Instantieer nooit Base<Wrong> voor een niet-gerelateerde klasse

Vergelijkingsoperatoren via CRTP

Je kunt een volledige set vergelijkingsoperatoren afleiden uit één operator< door over te erven van een vergelijkingshulpklasse.

#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;
}

Beveiliging met een protected constructor

Geef de basisklasse een protected constructor om onbedoeld gebruik ervan te voorkomen, zodat alleen afgeleide klassen deze kunnen maken.

#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 in standaardbibliotheken

CRTP komt voor in allerlei echte C++-bibliotheken.

  • std::enable_shared_from_this<T> gebruikt het
  • Veel wiskundige bibliotheken met expressietemplates, zoals Eigen, steunen erop
  • Bereiken en iteratorhulpfuncties gebruiken vergelijkbare patronen

Als je de vorm X : Base<X> herkent, kun je geavanceerde code gemakkelijker lezen.

Korte controle

Test je begrip van de CRTP-vorm.

Samenvatting

Je hebt het CRTP-idioom geleerd.

  • Derived : Base<Derived> geeft de basisklasse zijn concrete type
  • Een static_cast<T*>(this) maakt dispatch tijdens het compileren mogelijk
  • Geen vtable, kleinere objecten en inlinebare aanroepen
  • Wordt gebruikt voor tellers, vergelijkingsmixins en bibliotheekhulpfuncties
Gratis beginnen

Leer C++ met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
51
Lessen
203

Veelgestelde vragen

Is de les “Het CRTP-idioom” gratis?

Ja — je kunt hier op het web alle 3 lessen van het leerpad C++ Academy, waaronder “Het CRTP-idioom”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus C++ Academy bevat in totaal 4 lessen.

Wat leer ik in “Het CRTP-idioom”?

Curiously recurring template pattern Je oefent met C++ Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met C++ Academy te beginnen?

Ervaring vooraf is niet nodig. C++ Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 1 van 4.

Hoe lang duurt de les “Het CRTP-idioom”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over C++ Academy?

Ja. Elke les over C++ Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Het CRTP-idioom
  2. Statische polymorfie
  3. Mixins met CRTP
  4. Wanneer gebruikt u CRTP
← Terug naar C++ Academy