#include <iostream>
#include <map>
#include <ctime>
struct Base { virtual void foo() {} };
struct A : Base { void foo() {} };
struct B : Base { void foo() {} };
struct C : Base { void foo() {} };
A* protoA = new A; B* protoB = new B; C* protoC = new C;
enum Tag {a, b, c};
std::map<Tag, Base*> protoMap = { {a, protoA}, {b, protoB}, {c, protoC} };
void goo(Base* base) {base->foo();}
void hoo(Tag tag) {protoMap[tag]->foo();}
struct Timer {
const std::clock_t begin;
Timer() : begin (std::clock()) {}
~Timer() {
const std::clock_t end = std::clock();
std::cout << double (end - begin) / CLOCKS_PER_SEC << " seconds." << std::endl;
};
};
int main() {
const long N = 10000000;
{
Timer timer;
for (int i = 0; i < N; i++)
goo(new C); // using vtable
} // 0.445 seconds.
{
Timer timer;
for (int i = 0; i < N; i++)
hoo(c); // using map
} // 0.605 seconds.
std::cin.get();
}
Но мой тест использует только три производных класса, и я не знаю, как определить тысячи производных классов для правильной оценки. Кто-нибудь знает ответ уже, так что мне не нужно думать о том, как проводить лучшие тесты?
Я в ситуации, когда я могу легко использовать карту, но для повышения производительности с помощью vtable look-up потребуется перепроектировать много вещей, которые у меня уже есть (добавьте новый элемент данных в класс, определите новый конструктор, реализовать шаблон посетителя и т.д.).
Без сомнения, самый быстрый способ - это vtable.
Экспериментирование:
Вы должны запустить свой тест в аналогичных условиях. Нецелесообразно выделять новый элемент для каждого вызова для теста vtable, но не выделять ничего в подход карты.
Я проверил тест, используя подход vtable, используя указатель на уже выделенный элемент. Я получил 16 мс для vtable и 78 мс для подхода карты.
Если вы хотите пойти дальше и ралли сравнить 1000-й производные, вам придется работать с рекурсивным шаблоном.
Объяснение результата:
Обычно просмотр vtable использует фиксированное смещение в vtable объекта, а не поиск. Таким образом, даже с 1000 выводами вы будете иметь постоянное время реакции в O (1).
Карта должна будет выполнить дорогостоящую операцию поиска на клавише, то есть O (log (n)).
Дополнительные замечания:
Реализация карты, которую вы предлагаете, не будет работать в reallife, потому что вы всегда вызываете функцию-член для ONE SINGLE предопределенного объекта: тот, который вы сохранили на карте. Виртуальная функция будет работать с любым объектом семейства.