Статический и динамический полиморфизм в c++, Дмитрий...
DESCRIPTION
На примере некоторых архитектурных решений Крипты Дмитрий расскажет о способах реализации полиморфного поведения в программах на C++, о преимуществах и недостатках этих способов, а также о новых возможностях C++11.TRANSCRIPT
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
11
Виртуальный полиморфизм: минусы
Медленный вызов методовНадо поддерживать иерархию классовГрабли с виртуальными методамиПриходится иметь дело с T* или T&Статический метод не может быть
виртуальнымИнвариантность
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
«Виртуальный» вызов без virtuala.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 dispatchingtemplate <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 dispatchingtemplate <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 dispatchingtemplate <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 polymorphismclass 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 polymorphismclass 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)
Можно строить параллельные иерархии
27
Новые возможности C++11: лямбды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: лямбды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
34
Источники
1. http://www.inteks.ru/OOAD/P-Cources.OOAD.part1.pdf2. http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern3. http://www.cs.wustl.edu/~schmidt/PDF/External-Polymorphism.pdf4. http://www.generic-programming.org/languages/cpp/techniques.php5. http://eli.thegreenplace.net/2013/12/05/the-cost-of-dynamic-virtual-call
s-vs-static-crtp-dispatch-in-c/