Когда люди говорят о CRTP, в качестве примера часто приводят такой код:
Код: Выделить всё
template
class Base {
public:
void interface() {
static_cast(this)->implementation();
}
void foo() { ... }
};
class Derived : public Base {
public:
void implementation() { ... }
};
int main() {
Derived d;
d.interface();
d.foo();
}
Но я думаю, что, когда я использую наследование, я могу добиться того же эффекта.
< pre class="lang-cpp Prettyprint-override">
Код: Выделить всё
class Base1 {
public:
virtual void interface() = 0;
void foo() { ... }
};
class Derived1 : public Base1 {
public:
void interface() final { ... }
};
int main() {
Derived1 *d1 = new Derived1();
d1->interface();
d1->foo();
}
Но в данном случае , я не использовал полиморфизм. Но Base — это класс-шаблон. Это Base. На самом деле у нас есть информация о том, что это производное, и мы не можем использовать общий указатель Base*, который указывает на Base и Base одновременно время. Я считаю, что сравнивать его и Base* в наследовании несправедливо. Его следует сравнивать с Derived при наследовании. Я имею в виду, что когда мы можем получить тип Base, мы также можем получить тип Derived*.
Тогда, на мой взгляд, разница между этими двумя способами переписывания и совместного использования общего кода есть только то, что наследование добавит виртуальную таблицу в заголовок производного класса. Таким образом, эти два способа могут иметь некоторые различия в использовании памяти и скорости работы из-за разных размеров памяти. Эта память используется, чтобы помочь нам указать подкласс через указатель родительского класса и выполнить вызовы виртуальных функций, когда нам это нужно. Если такой ситуации в коде нет, выбираем CRTP, иначе наследуем.
Правильна ли моя идея? Что еще может делать CRTP, чего не может наследование?
Подробнее здесь: https://stackoverflow.com/questions/786 ... ge-of-crtp