Статический полиморфизм в С++

#include <iostream>

template<typename Impl>
struct renderer{
    void get(){
        static_cast<Impl*>(this)->get();
    }
};
struct open_gl : public renderer<open_gl>{
    void get(){
        std::cout << "OpenGL" << std::endl;
    }
};
struct direct_draw : public renderer<direct_draw>{
    void get(){
        std::cout << "DX" << std::endl;
    }
};
template<typename T>
void print_renderer(renderer<T> r){
    r.get();
}
int main() {
    auto gl = open_gl();
    auto dx = direct_draw();
    print_renderer(gl);
    print_renderer(dx);
}
  • Почему я не могу изменить параметр print_renderer на void print_renderer(const renderer<T> &r)? cannot convert 'this' pointer from 'const renderer<open_gl>' to 'renderer<open_gl> &' `

  • Почему возникает ошибка выполнения при переименовании метода get в open_gl из получить get1? Не должно ли это вызвать ошибку компилятора? Error = Stack overflow

** Примечание. Я использую последнюю версию MSVC

Ответ 1

1) Поскольку get не является функцией-членом const: он не может обещать, что не изменит ваш аргумент (const).

Вы можете объявить get как const, и он компилируется отлично:

void get() const { ... }

2) Будет вызываться базовый метод get, переходящий в бесконечную рекурсию: переполнение стека.

Если вы объявите свою функцию override (она должна быть виртуальной), компилятор выдает ошибку, если она не отменяет базовый метод:

void get1() override  { ... } // Compiler error
void get() override   { ... } // Ok

Примечание:

Название "Статический полиморфизм в С++", но я думаю, что вы неправильно поняли, что такое статический полиморфизм: он не должен (должен) использовать наследование (как и вы). Скорее, набор символов утилит времени компиляции будет статически "разрешать" вызовы функций для вас.

То есть вам не нужны связанные типы, вам не нужен базовый класс renderer, и вы можете просто сделать следующее (в этом случае переименование в get1 приведет к ошибке компилятора ):

#include <iostream>

struct open_gl {
    void get(){
        std::cout << "OpenGL" << std::endl;
    }
};
struct direct_draw {
    void get(){
        std::cout << "DX" << std::endl;
    }
};

template<typename T>
void print_renderer(T r){
    r.get();
}

int main() {
    auto gl = open_gl();
    auto dx = direct_draw();
    print_renderer(gl);
    print_renderer(dx);
}

Живая демонстрация

Ответ 2

  • Becuase get не отмечен const.
  • Потому что метод базового класса используется (не имеет значения для cast), и он переходит в бесконечный цикл.