Мазмунга өтүү

Кызыктай кайталануучу шаблон үлгүсү (CRTP) жана статикалык полиморфизм

Сабактын башталышы

Кызыктай кайталануучу шаблон үлгүсү (CRTP) жана статикалык полиморфизм

Виртуалдык функцияларга кошумча чыгымсыз альтернатива катары компиляция учурундагы диспетчеризация

Негизги идея: Кызыктай кайталануучу шаблон үлгүсү - бул класс өзү туунду класс менен параметрленген базалык шаблондон мураска алган идиома: class Widget : public Base<Widget>. Base так туунду типти компиляция учурунда билгендиктен, ал туунду класстын методдорун static_cast аркылуу түз чакыра алат, виртуалдык таблицасыз, кыйыр чакыруусуз жана толук ичине киргизүү (inlining) менен. Ушул түрдө полиморфизм компиляция учурундагы чечимге айланат.
Сабактын аягында сиз төмөнкүлөрдү аткара аласыз:
  • виртуалдык диспетчеризациянын аткаруу учурундагы баасын жана аны качан четтеткен жакшы экенин түшүндүрө аласыз,
  • CRTP түзүлүшүн окуп-жаза аласыз жана бул жерде static_cast эмне үчүн коопсуз экенин түшүнөсүз,
  • CRTP'ди статикалык интерфейстер үчүн, жалпы жүрүм-турумду примес (mixin) катары киргизүү үчүн жана оператордук шаблон кодду түзүү үчүн колдоносуз,
  • компиляция учурундагы диспетчеризацияны аткаруу учурундагы диспетчеризацияга каршы адилет салмактап, туура куралды тандай аласыз.

1. Кайталоо: аткаруу учурундагы полиморфизм канчага турат

Сиз виртуалдык функцияларды башталгыч жана орто курстардан билесиз. Методду virtual деп белгилеп, аны базалык көрсөткүч же шилтеме аркылуу чакырганда, компилятор конкреттүү типти биле албайт, ошондуктан диспетчеризация аткаруу учурунда виртуалдык функциялар таблицасы (vtable) аркылуу болот: ар бир полиморфтук объект өз классынын функция даректеринин таблицасына көрсөткөн жашыруун vptr алып жүрөт.

Бул ийкемдүүлүк акысыз эмес. Ар бир виртуалдык чакыруу - бул компилятор адатта алдын ала биле албаган көрсөткүч аркылуу болгон кыйыр чакыруу, демек:

  • максат компиляция учурунда белгисиз, ошондуктан чакырууну ичине киргизүүгө болбойт жана оптимизатор аны аркылуу көрө албайт;
  • ар бир объект бир көрсөткүчкө (vptr) чоңоёт, бул майда жана көп сандагы объекттер үчүн маанилүү;
  • кыйырдык ысык циклдерде тармактын туура эмес божомолдонушуна же кэш өткөрүп жиберүүсүнө себеп болушу мүмкүн.
struct Shape {
    virtual double area() const = 0;   // vtable аркылуу аткаруу учурунда чечилет
    virtual ~Shape() = default;
};

double totalArea(const std::vector<Shape*>& v) {
    double s = 0;
    for (const Shape* p : v)
        s += p->area();                 // кыйыр чакыруу, ичине киргизүүгө болбойт
    return s;
}

Коддун көбү үчүн бул баа анча маанилүү эмес, ал эми ийкемдүүлүк дал сизге керектүү нерсе. Бирок конкреттүү тип компиляция учурунда мурунтан белгилүү болсо - сандык ядро, туюнтма шаблону, контейнер адаптери - динамикалык диспетчеризацияга төлөө таза текке кетүү. CRTP «туунду класстын ишке ашырылышын чакыруу» формасын сактап, аны компиляция учурунда чечүүгө мүмкүндүк берет.

Бул сабакты YourAIZone платформасында улантыңыз

Толук сабакта — толук түшүндүрмө, чыгарылган мисалдар, көп кездешкен каталар, заматта текшерилүүчү тесттер жана ЖИ-репетитор. Конок катары дароо баштаңыз же прогрессти сактоо үчүн аккаунт түзүңүз.

Толук сабакта

  • Толук түшүндүрмө
  • Чыгарылган мисалдар
  • Көп кездешкен каталар жана алардан кантип качуу керек
  • Тест суроолору: 15
  • Тема боюнча суроолорго жооп берген ЖИ-репетитор
  • Окуучу, ата-эне жана мугалим үчүн прогрессти көзөмөлдөө