OO Design with C++: 6. Templates & Patterns

1,031 views
986 views

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,031
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • Alexander: Each pattern is a three-part rule, which expresses a relation between a certain context, a problem, and a solution. As an element in the world, each pattern is a relationship between a certain context, a certain system of forces which occurs repeatedly in that context, and a certain spatial configuration which allows these forces to resolve themselves. As an element of language, a pattern is an instruction, which shows how this spatial configuration can be used, over and over again, to resolve the given system of forces, wherever the context makes it relevant.
  • Alexander: Each pattern is a three-part rule, which expresses a relation between a certain context, a problem, and a solution. As an element in the world, each pattern is a relationship between a certain context, a certain system of forces which occurs repeatedly in that context, and a certain spatial configuration which allows these forces to resolve themselves. As an element of language, a pattern is an instruction, which shows how this spatial configuration can be used, over and over again, to resolve the given system of forces, wherever the context makes it relevant.
  • OO Design with C++: 6. Templates & Patterns

    1. 1. C++: шаблоны, часть 1 Дмитрий Штилерман, Рексофт
    2. 2. Шаблоны: прагматический подход <ul><li>В C++ шаблоны возникли из практических потребностей разработчиков библиотек. </li></ul><ul><li>Шаблоны классов: </li></ul><ul><ul><li>Обобщенные контейнеры. </li></ul></ul><ul><ul><li>Обобщенные потоки. </li></ul></ul><ul><li>Шаблоны функций: </li></ul><ul><ul><li>Замена стандартных макросов ANSI C </li></ul></ul><ul><ul><li>Операции над обобщенными контейнерами и потоками. </li></ul></ul>
    3. 3. Если бы не шаблоны классов... <ul><li>Указатели на «что-то» (void*)  отказ от статической типизации. </li></ul><ul><li>Указатели на искусственный базовый класс  неоправданное усложнение иерархии, злоупотребление наследованием. </li></ul>class Stack { void push(void*); void* pop(); }; void f() { Stack s; s.push((void*) new Cat); Dog* dog = (Dog*) s.pop(); dog->bark(); }; class StackElem {/*???*/}; class Stack { void push(StackElem*); StackElem* pop(); }; class Cat : public StackElem {}; class Dog : public StackElem {};
    4. 4. Если бы не шаблоны функций... <ul><li>Макросы  отказ от статической типизации, ошибки кодирования , неожиданности при вычислении . </li></ul><ul><li>Перегрузка  утомительное и чреватое ошибками копирование кода. </li></ul><ul><li>Указатели на искуственный базовый класс  см. выше. </li></ul>#define max(a,b) ((a>b) ? (a) : (b)) const Comparable& max(const Comparable&, const Comparable&); int max(int a, int b) {return (a>b) ? a : b;} short max(short a, short b) {return (a>b) ? a : b;} long max(long a, long b) {return (a>b) ? a : b;} float max(float a, float b) {return (a>b) ? a : b;} double max(double a, double b) {return (a>b) ? a : b;}
    5. 5. Когда использовать шаблоны - самый простой критерий <ul><li>Перечисленные выше примеры «кривого кода» - типичные индикаторы того, что пора применить шаблоны. </li></ul><ul><ul><li>Повторения одного и того же кода, отличающиеся только именами типов. </li></ul></ul><ul><ul><li>Искуственные базовые классы, не предоставляющие никакого содержательного интерфейса. </li></ul></ul><ul><ul><li>Сложные параметризованные макросы (не содержащие специальных лексических операций типа склейки или преобразования в строку). </li></ul></ul>
    6. 6. Параметры шаблонов <ul><li>Non-type parameters ( template<int N> ): на практике почти не употребляются (например, в стандартной библиотеке - ни одного). </li></ul><ul><li>Type parameters (template<class T>): подставляемый тип может быть любым, но делаются некоторые предположения о его интерфейсе («должна быть функция f , которую можно вот так вот вызвать»). </li></ul><ul><li>Важный момент : интерфейс, требуемый шаблоном, реализовывается без применения наследования («у нас просто есть функция f , мы ее не наследуем и не переопределяем »). </li></ul>
    7. 7. Instantiation <ul><li>Отношение классификатор-объект a.k.a. class-instance: </li></ul><ul><ul><li>class C {…}; C x; Объект x - экземпляр класса C (instance). </li></ul></ul><ul><ul><li>template<class T> class C {…}; C<D> x; Класс C<D> - экземпляр шаблона C (instantiated class). Объект x - экземпляр класса C<D> (instance). </li></ul></ul><ul><ul><li>template<class T> void f(T) {…} … f<int>(0); Функция f<int> - экземпляр шаблона f (instantiated function). </li></ul></ul><ul><li>Действие компилятора по созданию экземпляра шаблона - instantiation ( инстанциация? инстанцирование ? создание экземпляра ? ). </li></ul>
    8. 8. Шаблон как область действия <ul><li>Шаблон класса не есть класс! Следовательно, шаблон класса не есть область действия ( scope ). template<class T> class C {static void g();}; Нет никакой C::g! Есть C<int>::g, C<std::string>::g и т.д. </li></ul><ul><li>Как сделать шаблон областью действия (т.е. создавать функции/данные, относящиеся ко всем экземплярам шаблона)? Унаследовать шаблон от базового класса, не являющегося шаблоном. class B {static void g();}; template<class T> class C : … B {…}; </li></ul><ul><li>Какое наследование ( public/private, virtual etc. ) применить? Зависит от моделируемого отношения ( “is-a” etc. ) и интерфейса (public etc.), к которому относится имя (C::g). </li></ul>
    9. 9. Specialization <ul><li>Отдельная реализация шаблона при конкретных значениях одного или нескольких параметров. </li></ul><ul><li>Результат - класс или функция (если зафиксированы все параметры) или шаблон с меньшим числом параметров. </li></ul><ul><li>Применения: </li></ul><ul><ul><li>Оптимизированные версии. </li></ul></ul><ul><ul><li>Информационные классы (traits) . </li></ul></ul>template<class T> void MyCopy(T* dst, T* src, int n) { if(dst && src && (dst != src) for(int i = 0; i < n; i++) dst[i] = src[i]; } template<> void MyCopy<int>(int* dst, int* src, int n) {memmove(dst, src, n);}
    10. 10. Реализация шаблонов <ul><li>В первом приближении, шаблоны - это макросы с проверкой типов. </li></ul>template<class T> class Stack {public: Stack() {} void push(T) {…} T pop() {…} }; void f() { Stack<int> is; Stack<string> ss; } class Stack_int {public: Stack_int() {} void push(int) {…} int pop() {…} }; class Stack_string {…}; void f() { Stack_int } А что во втором приближении ? Проблема «code bloating». Template instantiation
    11. 11. Понятие связывания ( linkage) <ul><li>Файл (translation unit) C++ есть последовательность объявлений ( declarations ). Каждое объявление вводит одно или несколько имен ( names ). </li></ul><ul><li>Имя может иметь внешнее или внутреннее связывание ( external / internal linkage). </li></ul><ul><ul><li>Внешнее связывание  имя видно из других файлов. Примеры: глобальные функции; классы. </li></ul></ul><ul><ul><li>Внутреннее связывание  имя не видно из других файлов. Примеры: имена , объявленные как static, inline или const. </li></ul></ul><ul><li>Физический смысл: имена с внешним связыванием видны компоновщику через заголовок объектного файла . </li></ul><ul><li>Имя с внешним связыванием должно быть уникально в программе ( иначе - ошибка компоновки ). </li></ul>
    12. 12. Какое связывание имеет экземпляр шаблона ? <ul><li>Файлы компилируются независимо. Какое связывание имеет foo<X> в file1.cpp и file2.cpp? </li></ul><ul><li>Внешнее нельзя, т.к. будут дублирующиеся имена. </li></ul><ul><li>Внутреннее можно, но тогда копии кода будут содержаться в нескольких файлах (« code bloating », «раздувание кода»). </li></ul><ul><li>Стандарт молчит, имплементации выкручиваются. Основной способ - нестандартные компоновщик, формат объектного файла и специальный вид связывания. </li></ul><ul><li>Та же проблема с inline virtual методами. </li></ul>// foo.h template<class T> void foo(T* p) {p->xyz();} // file1.cpp #include “foo.h” void bar1(X* x) {foo(x);} // file2.cpp #include “foo.h” void bar2(X* x) {foo(x);}
    13. 13. Generic programming <ul><li>Немолодая идея (младше ATD , старше OOP ). </li></ul><ul><li>В оригинальном виде: максимально полное разделение структур данных и обрабатывающих их алгоритмов. </li></ul><ul><li>“ Programming with concepts” A concept is a family of abstractions that are all related by a common set of requirements, where the requirements consist of valid expressions, associated types, invariants and complexity guarantees. </li></ul><ul><li>В строго типизированных языках ( Ada, C++ ) приводит к механизму параметризованных типов . В безтиповых и близких к ним ( Smalltalk, скриптовые языки) получается само собой. </li></ul>
    14. 14. П аттерны (1) <ul><li>Существующие общие определения паттерна: </li></ul><ul><ul><li>A description of communicating objects and classes that are customized to solve a general problem in a particular context. (GoF) </li></ul></ul><ul><ul><li>A three-part rule, which expresses a relation between a certain context, a problem, and a solution. (Alexander) </li></ul></ul><ul><ul><li>An especially clever way of solving an entire particular class of problems. (Eckel) </li></ul></ul><ul><li>Более узкое определение паттерна с точки зрения современного OOD: </li></ul><ul><ul><li>Паттерн есть параметризованная кооперация. </li></ul></ul>
    15. 15. П аттерны (2) <ul><li>Два основных определения: </li></ul><ul><ul><li>Сommunicating objects that are customized to solve a general problem in a particular context. </li></ul></ul><ul><ul><li>П араметризованная кооперация. </li></ul></ul><ul><li>Как соотносятся эти два определения? </li></ul><ul><ul><li>«Кооперация»  « communicating objects », « general problem ». </li></ul></ul><ul><ul><li>«Параметризованная»  « customized », « particular context ». </li></ul></ul><ul><li>Какова связь с параметризованными типами и generic programming? </li></ul><ul><ul><li>Паттерн реализуется в виде набора взаимосвязанных шаблонов. </li></ul></ul><ul><ul><li>Паттерн используется путем подстановки в шаблоны классов, используемых в конкретном контексте. </li></ul></ul>
    16. 16. Пример: паттерн Observer

    ×