Допустим, у вас есть класс, который имеет несколько вариантов реализации, и по какому-то условию инстанцироваться должна только одна из реализаций. Например, как в шаблоне проектирования "Стратегия".
Разумеется, стандартное ООП-решение
float s;
enum Types { Type1, Type2 };
class MyClass
{
  class Implementation
  {
  public:
    virtual void f() = 0;
    virtual ~Implementation() {}
  };
  class Implementation1 : public Implementation
  {
  public:
    virtual void f() { s += 1.0f; }
  };
  class Implementation2 : public Implementation
  {
  public:
    virtual void f() { s -= 1.0f; }
  };
  Implementation *implementation;
public:
  MyClass(const Types type) : implementation(NULL)
  {
    switch(type)
    {
    case Type1: implementation = new Implementation1(); break;
    case Type2: implementation = new Implementation2(); break;
    default: throw exception();
    }
  }
  void f()
  {
    implementation->f();
  }
  ~MyClass()
  {
    delete implementaiton;
  }
};
с реализацией интерфейса приводит к тому, что на каждый вызов MyClass::f приходится разыменовывать два указателя: сам объект implementation, и потом в нём виртуальную функцию. В результате, например, миллиард вызовов работает примерно 23-24 секунды вместо 4 секунд обычной функции:
void f()
{
  s += 1.0f;
}
Что же с этим делать?
Желание хотя бы заранее разыменовать указатель на implementation сопряжено с трудностями. Объект типа IImpl существовать не может - из-за абстрактного класса. Может существовать только ссылка, но её обязательно нужно инициализировать в конструкторе, да ещё и в списке инициализации. Поэтому можно соорудить конструктор с созданием объекта реализации при помощи вспомогательной статической функции-фабрики, а ссылку на этот объект инициализировать сразу после его создания:
class MyClass
{
  /* ... */
  Implementation *implementation;
  Implementation &reference;
  static Implementation *createImplementation(const Types type)
  {
    switch(type)
    {
    case Type1: return new Implementation1();
    case Type2: return new Implementation2();
    default: throw exception();
    }
  }
  
public:
  MyClass(const Types type) : implementation(createImplementation(type)), reference(*implementation)
  {}
  void f()
  {
    reference.f();
  }
  ~MyClass()
  {
    delete implementaiton;
  }
};
И надо заметить, это нам почти никак не помогло - основной вклад в падение производительности привносит именно вызов виртуальной функции.
Разные реализации находятся в разных классах. Свести типы этих классов к единому, чтобы назначить этот тип полю класса, можно только наследованием. Появившийся в C++11 вариант с auto применим лишь к локальным переменным внутри функций, но не к членам класса и не к возвращаемым значениям функций. Отказаться от виртуальных функций тоже нельзя - не будут вызываться методы реализаций. Вовсе отказаться от типизации сложно: во-первых, нетипизированным бывает лишь указатель, но не ссылка, во-вторых, для вызова метода всё равно нужно знать тип класса. Но по крайней мере такой вариант можно попробовать: оставить лишь указатель на реализацию, а выбор виртуальной функции заменить на жёсткое условие.
class MyClass
{
  class Implementation1
  {
  public:
    void f() { s += 1.0f; }
  };
  class Implementation2
  {
  public:
    void f() { s -= 1.0f; }
  };
  void *implementation;
public:
  MyClass(const Types type) : implementation(NULL)
  {
    switch(type)
    {
    case Type1: implementation = new Implementation1(); break;
    case Type2: implementation = new Implementation2(); break;
    default: throw exception();
    }
  }
  void f()
  {
    switch(type)
    {
    case Type1: static_cast<Implementation1 *>(implementation)->f(); break;
    case Type2: static_cast<Implementation2 *>(implementation)->f(); break;
    default: throw exception();
    }
  }
  ~MyClass()
  {
    delete implementaiton;
  }
};
И этот вариант работает лишь чуть медленнее простой функции f: чуть больше 4 секунд. Обработка жёсткого условия происходит гораздо быстрее выборки из таблицы виртуальных функций классов.
Последний вариант: использовать идею шаблона проектирования "Lightweight" для случая инициализации. Инстанцировать все варианты реализации сразу, но сделать их лёгкими объектами, отложив инициализацию до момента выбора рабочего варианта. Затем, как и в предыдущем случае, использовать жёсткое условие:
class MyClass
{
  class Implementation1
  {
  public:
    Implementation1() { /* Тут пусто */ }
    void init() { /* Тут основная инициализация */ }
    void f() { s += 1.0f; }
  };
  class Implementation2
  {
  public:
    Implementation2() { /* Тут пусто */ }
    void init() { /* Тут основная инициализация */ }
    void f() { s -= 1.0f; }
  };
  Implementation1 implementation;
  Implementation2 implementation;  
public:
  MyClass(const Types type)
  {
    /* Выбираем, какой объект будет рабочим, остальные остаются неинициализированными и "лёгкими". */
    switch(type)
    {
    case Type1: implementation1.init(); break;
    case Type2: implementation2.init(); break;
    default: throw exception();
    }
  }
  void f()
  {
    switch(type)
    {
    case Type1: implementation1.f(); break;
    case Type2: implementation2.f(); break;
    default: throw exception();
    }
  }
};
И этот вариант работает так же быстро, как простая функция - около 4 секунд.