1
2 
Статический и 
динамический 
полиморфизм в C++ 
Дмитрий Леванов 
Ведущий разработчик Крипта
3 
Крипта 
 Отвечает на вопрос «Кто?» 
 Определяет интересы по поведению в 
интернете 
 Используется для таргетинга рекламы 
 От др.-греч. κρυπτή — крытый подземный ход, 
тайник
4 
Как учили Крипту 
+ Логи 
Обучение Контроль 
Матрикснет
5 
Крипта
6 
Разработка Крипты 
 Много логов в разных форматах 
 Сложные цепочки обработки 
 Высокие требования к производительности 
 Много одинаковой похожей логики 
 Хочется делать всё однообразно
7 
Модель распределенных 
вычислений MapReduce 
Дмитрий Леванов 
Ведущий разработчик Крипта
8 
Полиморфизм 
 Способ поставить в соответствие некой 
грамматической конструкции контекстно- 
зависимую семантику 
или, по-русски: 
 Текст программы [почти] один и тот же, а 
смысл разный
9 
Виртуальный полиморфизм 
class Base { 
virtual void do() { std::cout << “base”; } 
}; 
class Derived : public Base { 
virtual void do() { std::cout << “derived”; } 
}; 
Base* b = new Derived(); 
b->do(); // derived
Виртуальный полиморфизм: плюсы 
10 
 ООП-шненько 
 Типобезопасно 
 Работают фичи, зависящие от _vptr
Виртуальный полиморфизм: минусы 
 Медленный вызов методов 
 Надо поддерживать иерархию классов 
 Грабли с виртуальными методами 
 Приходится иметь дело с T* или T& 
 Статический метод не может быть виртуальным 
 Инвариантность 
11
12 
Зачастую все сводится к… 
void f(Handler* h) { 
h->do(); 
} 
//... 
f(new MyHandler());
13 
Зачастую все сводится к… 
void f(Handler* h) { 
h->do(); 
} 
//... 
f(new MyHandler()); 
template<typename H> 
void f(const H& h) { 
h.do(); 
} 
//... 
f(MyHandler());
14 
Продолжаем улучшать 
void f(Handler* h) { 
h->do(); 
} 
//... 
f(new MyHandler()); 
template<typename H> 
void f(const H& h) { 
h(); 
} 
//... 
f(MyHandler());
15 
Вообще хорошо! 
void f(Handler* h) { 
h->do(); 
} 
//... 
f(new MyHandler()); 
template<typename H> 
void f(const H& h) { 
h(); 
} 
//... 
f([]() { /* do */ });
16 
Или так 
void f(Handler* h) { 
h->do(); 
} 
//... 
f(new MyHandler()); 
template<typename H> 
void f() { 
H::do(); 
} 
//... 
f<MyHandler>();
17 
Статический полиморфизм: плюсы 
 Типобезопасно 
 Быстрый вызов методов 
 Не надо наследоваться 
 Не надо иметь дело с указателями 
 Можно использовать лямбды
Статический полиморфизм: минусы 
18 
 Нельзя положить в коллекцию 
 Сложно проверять правильность кода 
 Есть ограничения компилятора 
 Медленно компилируется 
 Может распухнуть бинарник 
 Не во всех IDE правильно работает 
автокомплит
19 
«Виртуальный» вызов без virtual 
a.k.a. Curiously Recurring Template Pattern 
template<typename Derived> 
class Base { 
void do() { 
static_cast<Derived*>(*this)::do(); 
} 
}; 
class MyDerived : public Base<MyDerived> { 
void do() { std::cout << "my derived"; } 
}; 
Base<MyDerived>* b = new MyDerived(); 
b->do(); // my derived
20 
Tag dispatching 
template <class InputIter, class Dist> 
void advance (InputIter& it, Dist n); 
template <class InputIter, class Dist> 
void advance(InputIter& i, Dist n) { 
while (n--) ++i; 
} 
template <class RndAcsIter, class Dist> 
void advance(RndAcsIter& i, Dist n) { 
i += n; 
}
21 
Tag dispatching 
template <class InputIter, class Dist> 
void advance (InputIter& it, Dist n); 
template <class InputIter, class Dist> 
void advance(InputIter& i, Dist n, input_iter_tag) { 
while (n--) ++i; 
} 
template <class RndAcsIter, class Dist> 
void advance(RndAcsIter& i, Dist n, rnd_acs_iter_tag) { 
i += n; 
}
22 
Tag dispatching 
template <class InputIter, class Dist> 
void advance (InputIter& it, Dist n) { 
typename iter_traits<InputIter>::iter_category cat; 
advance(i, n, cat); 
} 
template <class InputIter, class Dist> 
void advance(InputIter& i, Dist n, input_iter_tag) { 
while (n--) ++i; 
} 
template <class RndAcsIter, class Dist> 
void advance(RndAcsIter& i, Dist n, rnd_acs_iter_tag) { 
i += n; 
}
23 
Задача 
 Например, мы пишем дебаггер 
 Есть множество объектов, не связанных 
какой-либо иерархией 
 Хотим сложить их в одну коллекцию, 
проитерироваться по ней, и сдампить объекты 
int x = 10; 
Foo bar; 
objects.add(x); 
objects.add(bar); 
for (const auto& obj : objects) { 
obj.dump(); 
}
24 
External polymorphism 
class Dumpable { 
virtual void dump() const = 0; 
}; 
template<typename T> 
class ConcreteDumpable<T> : public Dumpable { 
const T& value; 
public: 
ConcreteDumpable(const T& value) : value(value) {} 
virtual void dump() const { 
::dump(value); 
} 
}; 
void dump(const Foo& foo) { 
foo.printToConsole(); 
}
25 
External polymorphism 
class Dumper { 
std::vector<Dumpable*> dumpables; 
public: 
template<typename T> 
void add(T& obj) { 
auto dumpable = new ConcreteDumpable<T>(obj); 
dumpables.push_back(dumpable); 
} 
void dumpAll() const { 
for (auto d : dumpables) { d->dump(); } 
} 
} dumper; 
int x = 10; 
Foo bar; 
dumper.add(x); 
dumper.add(foo); 
dumper.dumpAll();
26 
External polymorphism 
 Симбиоз виртуального и статического 
полиморфизма 
 Для поддержки нового типа T надо добавить 
только ::dump(T) 
 Можно строить параллельные иерархии
Новые возможности C++11: лямбды 
27 
int x = 10; 
vector<int> v = { 1, 2, 3 }; 
for_each(v.begin(), v.end(), [x](int i){cout << i+x;}); 
class Lambda { 
int x; 
public: 
Lambda(int x) : x(x) {} 
void operator( )(int i) {cout << i+x;} 
}; 
for_each(Lambda());
Новые возможности C++14: лямбды 
28 
int x = 10; 
vector<int> v = { 1, 2, 3 }; 
for_each(v.begin(), v.end(), [x](auto i){cout << i+x;}); 
class Lambda { 
int x; 
public: 
Lambda(int x) : x(x) {} 
template<typename T> 
void operator( )(T i) {cout << i+x;} 
};
29 
Новые возможности C++11: 
std::function 
using namespace std; 
void print(int i) { cout << i; } 
struct Print { 
void operator()(int i) {cout << i+x;} 
} 
function<void(int)> p1 = print; 
function<void(int)> p1 = Print; 
function<void(int)> p1 = [](int i) {cout << i+x;};
30 
Новые возможности C++11: 
std::function 
using namespace std; 
void print(int i) { cout << i; } 
struct Print { 
void operator()(int i) {cout << i+x;} 
} 
function<void(int)> p1 = print; 
function<void(int)> p1 = Print; 
function<void(int)> p1 = [](int i) {cout << i+x;};
31 
Новые возможности C++11: 
std::function 
 Медленные (virtual под капотом) 
 Обеспечивают поддержку концептов 
 Позволяют сохранить исполняемые объекты 
 Не замена шаблонам и виртуальным методам!
32 
Топ фич (субъективный) 
1. Обычный метод/функция 
2. Шаблонный метод/функция (+лямбды) 
3. Шаблонный класс (+CRTP) 
4. Виртуальный метод 
5. Внешний полиморфизм 
6. std::function
33 
Спасибо за внимание! 
Дмитрий Леванов 
Ведущий разработчик Крипта 
levanov@yandex-team.ru
34 
Источники 
1. http://www.inteks.ru/OOAD/P-Cources.OOAD.part1.pdf 
2. http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern 
3. http://www.cs.wustl.edu/~schmidt/PDF/External-Polymorphism.pdf 
4. http://www.generic-programming.org/languages/cpp/techniques.php 
5. http://eli.thegreenplace.net/2013/12/05/the-cost-of-dynamic-virtual-calls- 
vs-static-crtp-dispatch-in-c/

Статический и динамический полиморфизм в C++, Дмитрий Леванов

  • 1.
  • 2.
    2 Статический и динамический полиморфизм в C++ Дмитрий Леванов Ведущий разработчик Крипта
  • 3.
    3 Крипта Отвечает на вопрос «Кто?»  Определяет интересы по поведению в интернете  Используется для таргетинга рекламы  От др.-греч. κρυπτή — крытый подземный ход, тайник
  • 4.
    4 Как училиКрипту + Логи Обучение Контроль Матрикснет
  • 5.
  • 6.
    6 Разработка Крипты  Много логов в разных форматах  Сложные цепочки обработки  Высокие требования к производительности  Много одинаковой похожей логики  Хочется делать всё однообразно
  • 7.
    7 Модель распределенных вычислений MapReduce Дмитрий Леванов Ведущий разработчик Крипта
  • 8.
    8 Полиморфизм Способ поставить в соответствие некой грамматической конструкции контекстно- зависимую семантику или, по-русски:  Текст программы [почти] один и тот же, а смысл разный
  • 9.
    9 Виртуальный полиморфизм class Base { virtual void do() { std::cout << “base”; } }; class Derived : public Base { virtual void do() { std::cout << “derived”; } }; Base* b = new Derived(); b->do(); // derived
  • 10.
    Виртуальный полиморфизм: плюсы 10  ООП-шненько  Типобезопасно  Работают фичи, зависящие от _vptr
  • 11.
    Виртуальный полиморфизм: минусы  Медленный вызов методов  Надо поддерживать иерархию классов  Грабли с виртуальными методами  Приходится иметь дело с T* или T&  Статический метод не может быть виртуальным  Инвариантность 11
  • 12.
    12 Зачастую всесводится к… void f(Handler* h) { h->do(); } //... f(new MyHandler());
  • 13.
    13 Зачастую всесводится к… void f(Handler* h) { h->do(); } //... f(new MyHandler()); template<typename H> void f(const H& h) { h.do(); } //... f(MyHandler());
  • 14.
    14 Продолжаем улучшать void f(Handler* h) { h->do(); } //... f(new MyHandler()); template<typename H> void f(const H& h) { h(); } //... f(MyHandler());
  • 15.
    15 Вообще хорошо! void f(Handler* h) { h->do(); } //... f(new MyHandler()); template<typename H> void f(const H& h) { h(); } //... f([]() { /* do */ });
  • 16.
    16 Или так void f(Handler* h) { h->do(); } //... f(new MyHandler()); template<typename H> void f() { H::do(); } //... f<MyHandler>();
  • 17.
    17 Статический полиморфизм:плюсы  Типобезопасно  Быстрый вызов методов  Не надо наследоваться  Не надо иметь дело с указателями  Можно использовать лямбды
  • 18.
    Статический полиморфизм: минусы 18  Нельзя положить в коллекцию  Сложно проверять правильность кода  Есть ограничения компилятора  Медленно компилируется  Может распухнуть бинарник  Не во всех IDE правильно работает автокомплит
  • 19.
    19 «Виртуальный» вызовбез virtual a.k.a. Curiously Recurring Template Pattern template<typename Derived> class Base { void do() { static_cast<Derived*>(*this)::do(); } }; class MyDerived : public Base<MyDerived> { void do() { std::cout << "my derived"; } }; Base<MyDerived>* b = new MyDerived(); b->do(); // my derived
  • 20.
    20 Tag dispatching template <class InputIter, class Dist> void advance (InputIter& it, Dist n); template <class InputIter, class Dist> void advance(InputIter& i, Dist n) { while (n--) ++i; } template <class RndAcsIter, class Dist> void advance(RndAcsIter& i, Dist n) { i += n; }
  • 21.
    21 Tag dispatching template <class InputIter, class Dist> void advance (InputIter& it, Dist n); template <class InputIter, class Dist> void advance(InputIter& i, Dist n, input_iter_tag) { while (n--) ++i; } template <class RndAcsIter, class Dist> void advance(RndAcsIter& i, Dist n, rnd_acs_iter_tag) { i += n; }
  • 22.
    22 Tag dispatching template <class InputIter, class Dist> void advance (InputIter& it, Dist n) { typename iter_traits<InputIter>::iter_category cat; advance(i, n, cat); } template <class InputIter, class Dist> void advance(InputIter& i, Dist n, input_iter_tag) { while (n--) ++i; } template <class RndAcsIter, class Dist> void advance(RndAcsIter& i, Dist n, rnd_acs_iter_tag) { i += n; }
  • 23.
    23 Задача Например, мы пишем дебаггер  Есть множество объектов, не связанных какой-либо иерархией  Хотим сложить их в одну коллекцию, проитерироваться по ней, и сдампить объекты int x = 10; Foo bar; objects.add(x); objects.add(bar); for (const auto& obj : objects) { obj.dump(); }
  • 24.
    24 External polymorphism class Dumpable { virtual void dump() const = 0; }; template<typename T> class ConcreteDumpable<T> : public Dumpable { const T& value; public: ConcreteDumpable(const T& value) : value(value) {} virtual void dump() const { ::dump(value); } }; void dump(const Foo& foo) { foo.printToConsole(); }
  • 25.
    25 External polymorphism class Dumper { std::vector<Dumpable*> dumpables; public: template<typename T> void add(T& obj) { auto dumpable = new ConcreteDumpable<T>(obj); dumpables.push_back(dumpable); } void dumpAll() const { for (auto d : dumpables) { d->dump(); } } } dumper; int x = 10; Foo bar; dumper.add(x); dumper.add(foo); dumper.dumpAll();
  • 26.
    26 External polymorphism  Симбиоз виртуального и статического полиморфизма  Для поддержки нового типа T надо добавить только ::dump(T)  Можно строить параллельные иерархии
  • 27.
    Новые возможности C++11:лямбды 27 int x = 10; vector<int> v = { 1, 2, 3 }; for_each(v.begin(), v.end(), [x](int i){cout << i+x;}); class Lambda { int x; public: Lambda(int x) : x(x) {} void operator( )(int i) {cout << i+x;} }; for_each(Lambda());
  • 28.
    Новые возможности C++14:лямбды 28 int x = 10; vector<int> v = { 1, 2, 3 }; for_each(v.begin(), v.end(), [x](auto i){cout << i+x;}); class Lambda { int x; public: Lambda(int x) : x(x) {} template<typename T> void operator( )(T i) {cout << i+x;} };
  • 29.
    29 Новые возможностиC++11: std::function using namespace std; void print(int i) { cout << i; } struct Print { void operator()(int i) {cout << i+x;} } function<void(int)> p1 = print; function<void(int)> p1 = Print; function<void(int)> p1 = [](int i) {cout << i+x;};
  • 30.
    30 Новые возможностиC++11: std::function using namespace std; void print(int i) { cout << i; } struct Print { void operator()(int i) {cout << i+x;} } function<void(int)> p1 = print; function<void(int)> p1 = Print; function<void(int)> p1 = [](int i) {cout << i+x;};
  • 31.
    31 Новые возможностиC++11: std::function  Медленные (virtual под капотом)  Обеспечивают поддержку концептов  Позволяют сохранить исполняемые объекты  Не замена шаблонам и виртуальным методам!
  • 32.
    32 Топ фич(субъективный) 1. Обычный метод/функция 2. Шаблонный метод/функция (+лямбды) 3. Шаблонный класс (+CRTP) 4. Виртуальный метод 5. Внешний полиморфизм 6. std::function
  • 33.
    33 Спасибо завнимание! Дмитрий Леванов Ведущий разработчик Крипта levanov@yandex-team.ru
  • 34.
    34 Источники 1.http://www.inteks.ru/OOAD/P-Cources.OOAD.part1.pdf 2. http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern 3. http://www.cs.wustl.edu/~schmidt/PDF/External-Polymorphism.pdf 4. http://www.generic-programming.org/languages/cpp/techniques.php 5. http://eli.thegreenplace.net/2013/12/05/the-cost-of-dynamic-virtual-calls- vs-static-crtp-dispatch-in-c/