SlideShare a Scribd company logo
C++: шаблоны, часть 1 Дмитрий Штилерман, Рексофт
Шаблоны:  прагматический подход В  C++  шаблоны возникли из практических потребностей разработчиков библиотек. Шаблоны классов: Обобщенные контейнеры. Обобщенные потоки. Шаблоны функций: Замена стандартных макросов  ANSI C Операции над обобщенными контейнерами и потоками.
Если бы не шаблоны классов... Указатели на «что-то»  (void*)    отказ от статической типизации. Указатели на искусственный базовый класс      неоправданное усложнение иерархии, злоупотребление наследованием. 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  {};
Если бы не шаблоны функций... Макросы     отказ от статической типизации, ошибки кодирования , неожиданности при вычислении . Перегрузка    утомительное и чреватое ошибками копирование кода. Указатели на искуственный базовый класс      см. выше. #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;}
Когда использовать шаблоны - самый простой критерий Перечисленные выше примеры  «кривого кода» - типичные индикаторы того, что пора применить шаблоны. Повторения одного и того же кода, отличающиеся только именами типов. Искуственные базовые классы, не предоставляющие никакого содержательного интерфейса.  Сложные параметризованные макросы (не содержащие специальных лексических операций типа склейки или преобразования в строку).
Параметры шаблонов Non-type parameters ( template<int N> ): на практике почти не употребляются (например, в стандартной библиотеке - ни одного). Type parameters (template<class T>):  подставляемый тип может быть любым, но делаются некоторые предположения о его интерфейсе («должна быть функция  f , которую можно вот так вот вызвать»). Важный момент :  интерфейс, требуемый шаблоном, реализовывается без применения наследования («у нас  просто  есть функция  f ,  мы ее не наследуем и не переопределяем »).
Instantiation Отношение классификатор-объект  a.k.a.  class-instance: class C {…}; C x; Объект  x -  экземпляр класса  C (instance). template<class T> class C {…}; C<D> x; Класс  C<D> -  экземпляр шаблона  C (instantiated class). Объект  x -  экземпляр класса  C<D> (instance).   template<class T> void f(T) {…} … f<int>(0); Функция  f<int> -  экземпляр шаблона  f (instantiated function). Действие компилятора по созданию экземпляра шаблона -  instantiation ( инстанциация? инстанцирование ?  создание экземпляра ? ).
Шаблон  как  область действия Шаблон класса не есть класс! Следовательно, шаблон класса не есть область действия ( scope ).  template<class T> class C {static void g();}; Нет никакой  C::g!  Есть  C<int>::g, C<std::string>::g  и т.д. Как сделать шаблон областью действия (т.е. создавать функции/данные, относящиеся ко всем экземплярам шаблона)? Унаследовать шаблон от базового класса, не являющегося шаблоном. class B {static void g();}; template<class T> class C : … B {…}; Какое наследование ( public/private, virtual etc. ) применить? Зависит от моделируемого отношения ( “is-a” etc. ) и интерфейса (public etc.), к которому относится  имя (C::g).
Specialization Отдельная реализация шаблона при конкретных значениях одного или нескольких параметров. Результат - класс или функция (если зафиксированы все параметры) или шаблон с меньшим числом параметров. Применения: Оптимизированные версии. Информационные классы  (traits) . 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);}
Реализация шаблонов В первом приближении, шаблоны - это макросы с проверкой типов. 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
Понятие  связывания ( linkage) Файл (translation unit) C++  есть последовательность объявлений ( declarations ). Каждое объявление вводит одно или несколько имен ( names ). Имя может иметь внешнее или внутреннее связывание ( external / internal linkage). Внешнее связывание    имя видно из других файлов. Примеры: глобальные функции;  классы.   Внутреннее связывание    имя не видно из других файлов. Примеры:  имена , объявленные как static, inline  или  const. Физический смысл: имена с внешним связыванием видны компоновщику  через заголовок объектного файла . Имя с внешним связыванием должно быть уникально в программе ( иначе - ошибка компоновки ).
Какое  связывание имеет экземпляр шаблона ? Файлы компилируются независимо. Какое связывание имеет foo<X>  в  file1.cpp  и  file2.cpp? Внешнее нельзя, т.к. будут дублирующиеся имена. Внутреннее можно, но тогда копии кода будут содержаться в нескольких файлах (« code bloating », «раздувание кода»). Стандарт молчит, имплементации выкручиваются. Основной способ - нестандартные компоновщик, формат объектного файла и специальный вид связывания. Та же проблема с  inline virtual  методами. // 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);}
Generic programming Немолодая идея (младше  ATD , старше  OOP ). В оригинальном виде: максимально полное разделение структур данных и обрабатывающих их алгоритмов. “ 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. В строго типизированных языках ( Ada, C++ ) приводит к механизму  параметризованных типов . В безтиповых и близких к ним  ( Smalltalk,  скриптовые языки) получается само собой.
П аттерны (1) Существующие общие определения паттерна: A description of communicating objects and classes that are customized to solve a general problem in a particular context.  (GoF) A three-part rule, which expresses a relation between a certain context, a problem, and a solution.  (Alexander) An especially clever way of solving an entire particular class of problems.  (Eckel) Более узкое определение паттерна с точки зрения современного  OOD: Паттерн есть параметризованная кооперация.
П аттерны (2) Два основных определения: Сommunicating objects that are customized to solve a general problem in a particular context. П араметризованная кооперация. Как соотносятся эти два определения? «Кооперация»    « communicating objects », « general problem ». «Параметризованная»    « customized », « particular context ». Какова связь с  параметризованными типами и generic programming? Паттерн   реализуется в виде набора взаимосвязанных шаблонов. Паттерн используется путем подстановки в шаблоны классов, используемых в конкретном контексте.
Пример: паттерн Observer

More Related Content

PPT
OO Design with C++: 3. Inheritance, part 3
PDF
Christofides
PPTX
презентация
PDF
Amplifying Reduction Non Approx
PDF
Xen virtualization
PDF
îïèñàíèå
PDF
Установка производства полимербитума вязкого ПБВ, модификация битумов полимер...
PDF
Написание DSL в Perl
OO Design with C++: 3. Inheritance, part 3
Christofides
презентация
Amplifying Reduction Non Approx
Xen virtualization
îïèñàíèå
Установка производства полимербитума вязкого ПБВ, модификация битумов полимер...
Написание DSL в Perl

What's hot (9)

PDF
Grape Trends 2009
PDF
Xrumme
PPT
присяжный Root Conf2009 Beta 1
PDF
226 Ch
PPSX
советы, которые спасут ваш компьютер
PPSX
классификация вредоносного по
PDF
Thrift Hl 2
PDF
Mobile Influence Kyivstar
PPT
Lecture4 5 aлгоритм_түүний_шинжчанар
Grape Trends 2009
Xrumme
присяжный Root Conf2009 Beta 1
226 Ch
советы, которые спасут ваш компьютер
классификация вредоносного по
Thrift Hl 2
Mobile Influence Kyivstar
Lecture4 5 aлгоритм_түүний_шинжчанар
Ad

More from Dmitry Stillermann (7)

PPTX
DiSC Model in Practice
PPTX
Как расти самому, помогая расти другим — практическое применение Management T...
PPT
OO Design with C++: 4. Design Principles, part 1
PPT
OO Design with C++: 5. Design Principles, part 2
PPT
OO Design with C++: 2. Inheritance, part 2
PPT
OO Design with C++: 1. Inheritance, part 1
PPT
OO Design with C++: 0. Intro
DiSC Model in Practice
Как расти самому, помогая расти другим — практическое применение Management T...
OO Design with C++: 4. Design Principles, part 1
OO Design with C++: 5. Design Principles, part 2
OO Design with C++: 2. Inheritance, part 2
OO Design with C++: 1. Inheritance, part 1
OO Design with C++: 0. Intro
Ad

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

  • 1. C++: шаблоны, часть 1 Дмитрий Штилерман, Рексофт
  • 2. Шаблоны: прагматический подход В C++ шаблоны возникли из практических потребностей разработчиков библиотек. Шаблоны классов: Обобщенные контейнеры. Обобщенные потоки. Шаблоны функций: Замена стандартных макросов ANSI C Операции над обобщенными контейнерами и потоками.
  • 3. Если бы не шаблоны классов... Указатели на «что-то» (void*)  отказ от статической типизации. Указатели на искусственный базовый класс  неоправданное усложнение иерархии, злоупотребление наследованием. 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. Если бы не шаблоны функций... Макросы  отказ от статической типизации, ошибки кодирования , неожиданности при вычислении . Перегрузка  утомительное и чреватое ошибками копирование кода. Указатели на искуственный базовый класс  см. выше. #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. Когда использовать шаблоны - самый простой критерий Перечисленные выше примеры «кривого кода» - типичные индикаторы того, что пора применить шаблоны. Повторения одного и того же кода, отличающиеся только именами типов. Искуственные базовые классы, не предоставляющие никакого содержательного интерфейса. Сложные параметризованные макросы (не содержащие специальных лексических операций типа склейки или преобразования в строку).
  • 6. Параметры шаблонов Non-type parameters ( template<int N> ): на практике почти не употребляются (например, в стандартной библиотеке - ни одного). Type parameters (template<class T>): подставляемый тип может быть любым, но делаются некоторые предположения о его интерфейсе («должна быть функция f , которую можно вот так вот вызвать»). Важный момент : интерфейс, требуемый шаблоном, реализовывается без применения наследования («у нас просто есть функция f , мы ее не наследуем и не переопределяем »).
  • 7. Instantiation Отношение классификатор-объект a.k.a. class-instance: class C {…}; C x; Объект x - экземпляр класса C (instance). template<class T> class C {…}; C<D> x; Класс C<D> - экземпляр шаблона C (instantiated class). Объект x - экземпляр класса C<D> (instance). template<class T> void f(T) {…} … f<int>(0); Функция f<int> - экземпляр шаблона f (instantiated function). Действие компилятора по созданию экземпляра шаблона - instantiation ( инстанциация? инстанцирование ? создание экземпляра ? ).
  • 8. Шаблон как область действия Шаблон класса не есть класс! Следовательно, шаблон класса не есть область действия ( scope ). template<class T> class C {static void g();}; Нет никакой C::g! Есть C<int>::g, C<std::string>::g и т.д. Как сделать шаблон областью действия (т.е. создавать функции/данные, относящиеся ко всем экземплярам шаблона)? Унаследовать шаблон от базового класса, не являющегося шаблоном. class B {static void g();}; template<class T> class C : … B {…}; Какое наследование ( public/private, virtual etc. ) применить? Зависит от моделируемого отношения ( “is-a” etc. ) и интерфейса (public etc.), к которому относится имя (C::g).
  • 9. Specialization Отдельная реализация шаблона при конкретных значениях одного или нескольких параметров. Результат - класс или функция (если зафиксированы все параметры) или шаблон с меньшим числом параметров. Применения: Оптимизированные версии. Информационные классы (traits) . 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. Реализация шаблонов В первом приближении, шаблоны - это макросы с проверкой типов. 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. Понятие связывания ( linkage) Файл (translation unit) C++ есть последовательность объявлений ( declarations ). Каждое объявление вводит одно или несколько имен ( names ). Имя может иметь внешнее или внутреннее связывание ( external / internal linkage). Внешнее связывание  имя видно из других файлов. Примеры: глобальные функции; классы. Внутреннее связывание  имя не видно из других файлов. Примеры: имена , объявленные как static, inline или const. Физический смысл: имена с внешним связыванием видны компоновщику через заголовок объектного файла . Имя с внешним связыванием должно быть уникально в программе ( иначе - ошибка компоновки ).
  • 12. Какое связывание имеет экземпляр шаблона ? Файлы компилируются независимо. Какое связывание имеет foo<X> в file1.cpp и file2.cpp? Внешнее нельзя, т.к. будут дублирующиеся имена. Внутреннее можно, но тогда копии кода будут содержаться в нескольких файлах (« code bloating », «раздувание кода»). Стандарт молчит, имплементации выкручиваются. Основной способ - нестандартные компоновщик, формат объектного файла и специальный вид связывания. Та же проблема с inline virtual методами. // 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. Generic programming Немолодая идея (младше ATD , старше OOP ). В оригинальном виде: максимально полное разделение структур данных и обрабатывающих их алгоритмов. “ 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. В строго типизированных языках ( Ada, C++ ) приводит к механизму параметризованных типов . В безтиповых и близких к ним ( Smalltalk, скриптовые языки) получается само собой.
  • 14. П аттерны (1) Существующие общие определения паттерна: A description of communicating objects and classes that are customized to solve a general problem in a particular context. (GoF) A three-part rule, which expresses a relation between a certain context, a problem, and a solution. (Alexander) An especially clever way of solving an entire particular class of problems. (Eckel) Более узкое определение паттерна с точки зрения современного OOD: Паттерн есть параметризованная кооперация.
  • 15. П аттерны (2) Два основных определения: Сommunicating objects that are customized to solve a general problem in a particular context. П араметризованная кооперация. Как соотносятся эти два определения? «Кооперация»  « communicating objects », « general problem ». «Параметризованная»  « customized », « particular context ». Какова связь с параметризованными типами и generic programming? Паттерн реализуется в виде набора взаимосвязанных шаблонов. Паттерн используется путем подстановки в шаблоны классов, используемых в конкретном контексте.

Editor's Notes

  • #15: 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.
  • #16: 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.