0Pricing
C++ Academy · Урок

Миксины с CRTP

Составляйте поведение во время компиляции

«Миксины с CRTP» — бесплатный урок C++ Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.

Что такое примесь?

Примесь — это небольшой повторно используемый элемент поведения, который можно включить в класс. С помощью CRTP примеси добавляют функциональность во время компиляции, при этом обращаясь к классу-носителю.

Простая примесь

Эта примесь добавляет метод print_twice, который предполагает, что класс-носитель предоставляет value().

#include <iostream>

template <typename T>
struct PrintTwice {
    void print_twice() const {
        auto v = static_cast<const T*>(this)->value();
        std::cout << v << " " << v << "\n";
    }
};

struct Box : PrintTwice<Box> {
    int value() const { return 7; }
};

int main() {
    Box{}.print_twice();
    return 0;
}

Композиция нескольких примесей

Вы можете одновременно наследоваться от нескольких примесей CRTP, объединяя независимые варианты поведения в одном классе.

#include <iostream>

template <typename T>
struct Loggable {
    void log() const { std::cout << "log: " << static_cast<const T*>(this)->id() << "\n"; }
};

template <typename T>
struct Resettable {
    void reset() { static_cast<T*>(this)->set(0); }
};

struct Device : Loggable<Device>, Resettable<Device> {
    int v = 5;
    int id() const { return v; }
    void set(int x) { v = x; }
};

int main() {
    Device d;
    d.log();
    d.reset();
    d.log();
    return 0;
}

Примеси тоже добавляют состояние

Примесь может хранить собственные члены данных, которые становятся частью компоновки составного объекта.

#include <iostream>

template <typename T>
struct Tagged {
    int tag = 0;
    void set_tag(int t) { tag = t; }
    int get_tag() const { return tag; }
};

struct Item : Tagged<Item> {
    const char* name = "item";
};

int main() {
    Item it;
    it.set_tag(42);
    std::cout << it.name << " " << it.get_tag() << "\n";
    return 0;
}

Примесь и обычное наследование

Примесь CRTP отличается от обычного наследования тем, что базовый класс может обращаться вниз, к производному классу. Обычные базовые классы не могут вызывать методы, существующие только в производном типе, без виртуальных функций.

Проектирование на основе политик

Примеси позволяют использовать проектирование на основе политик: варианты поведения выбираются во время компиляции через выбор примесей, от которых выполняется наследование, подобно тому как std::vector принимает политику распределителя памяти.

Порядок и компоновка

При объединении примесей порядок базовых классов влияет на порядок конструирования и компоновку объекта. Сохраняйте примеси независимыми, чтобы порядок не влиял на корректность.

  • Конструируйте в порядке объявления базовых классов
  • Избегайте примесей, зависящих друг от друга

Добавление примеси равенства

Здесь примесь создаёт operator!= на основе операции равенства класса-носителя.

#include <iostream>

template <typename T>
struct EqualityMixin {
    friend bool operator!=(const T& a, const T& b) { return !(a == b); }
};

struct P : EqualityMixin<P> {
    int x;
    P(int v) : x(v) {}
    friend bool operator==(const P& a, const P& b) { return a.x == b.x; }
};

int main() {
    std::cout << (P(1) != P(2)) << "\n";
    return 0;
}

Условные примеси

Вы можете включить примесь только при выполнении условия, объединив наследование с std::conditional и выбрав между настоящей примесью и пустой примесью.

Оптимизация пустого базового класса

Примеси, не содержащие членов данных, получают преимущество от оптимизации пустого базового класса: компилятор не выделяет для них дополнительных байтов, поэтому объединение множества примесей без состояния ничего не стоит с точки зрения размера.

#include <iostream>

template <typename T>
struct A {};
template <typename T>
struct B {};

struct C : A<C>, B<C> {
    int x;
};

int main() {
    std::cout << (sizeof(C) == sizeof(int)) << "\n";
    return 0;
}

Когда стоит использовать примеси

Примеси особенно полезны, когда многим классам нужны одинаковые независимые варианты поведения (журналирование, подсчёт, сравнение). Они помещают каждое поведение в одно место и объединяются без затрат во время выполнения.

Быстрая проверка

Проверьте, насколько хорошо Вы усвоили примеси CRTP.

Повторение

Вы научились создавать примеси с помощью CRTP.

  • Примеси объединяют независимые варианты поведения во время компиляции
  • Они могут обращаться к классу-носителю и хранить состояние
  • Примеси без состояния ничего не стоят благодаря оптимизации пустого базового класса
  • Они отлично подходят для политик журналирования, сравнения и подсчёта

Часто задаваемые вопросы

Урок «Миксины с CRTP» бесплатный?

Да — полный текст урока «Миксины с CRTP» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.

Чему я научусь в уроке «Миксины с CRTP»?

Составляйте поведение во время компиляции Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C++ Academy?

Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Миксины с CRTP»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C++ Academy?

Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Идиома CRTP
  2. Статический полиморфизм
  3. Миксины с CRTP
  4. Когда использовать CRTP
← Назад к C++ Academy