Есть два пути.
Первый - указать интерфейс статически для структуры типов:
template <class Derived>
struct base {
void foo() {
static_cast<Derived *>(this)->foo();
};
};
struct my_type : base<my_type> {
void foo(); // required to compile.
};
struct your_type : base<your_type> {
void foo(); // required to compile.
};
Во-вторых, избегая использования идиомы «ссылка на базу» или «указатель на базу», и выполняйте подключение во время компиляции. Используя приведенное выше определение, вы можете иметь функции шаблона, которые выглядят так:
template <class T> // T is deduced at compile-time
void bar(base<T> & obj) {
obj.foo(); // will do static dispatch
}
struct not_derived_from_base { }; // notice, not derived from base
// ...
my_type my_instance;
your_type your_instance;
not_derived_from_base invalid_instance;
bar(my_instance); // will call my_instance.foo()
bar(your_instance); // will call your_instance.foo()
bar(invalid_instance); // compile error, cannot deduce correct overload
Таким образом, объединение определения структуры / интерфейса и вывода типа времени компиляции в ваших функциях позволяет вам выполнять статическую диспетчеризацию вместо динамической диспетчеризации. В этом суть статического полиморфизма.