Объектно-ориентированное программирование на C++, страница 5
Описание файла
PDF-файл из архива "Объектно-ориентированное программирование на C++", который расположен в категории "". Всё это находится в предмете "информатика" из 1 семестр, которые можно найти в файловом архиве МГТУ им. Н.Э.Баумана. Не смотря на прямую связь этого архива с МГТУ им. Н.Э.Баумана, его также можно найти и в других разделах. Архив можно найти в разделе "книги и методические указания", в предмете "информатика" в общих файлах.
Просмотр PDF-файла онлайн
Текст 5 страницы из PDF
at (1 ,0) = 2;a . at (2 ,0) = 3;b . at (0 ,0) = 1;b . at (0 ,1) = 2;b . at (0 ,2) = 3;multiply < Matrix , int , 3 , 1 , 3 >( c ,a , b );Автоматическое выведение фактических параметров шаблона функции позволяет упростить вызов функции multiply:multiply (c ,a , b );57 / 99Требования к фактическим параметрамшаблоновБазовыесведенияОбобщённоепрограммированиеОбъявлениешаблоновПорождениекодаСпециализацияшаблоновПерегрузкаоперацийИсключенияТело шаблона накладывает требования на его фактическиепараметры.
Например, в теле шаблона функции multiplyподразумевается, что значения типа M – это объекты, имеющие метод at, который возвращает ссылку на значение,к которому могут быть применены операции сложения иумножения.Если фактические параметры шаблона не удовлетворяюттребованиям, инстанциация шаблона с этими фактическимипараметрами приведёт к ошибке времени компиляции.Например,template < typename T , int M , int N >struct Array2D { T a [ M ][ N ]; };...Array2D < int ,3 ,1 > x ;Array2D < int ,1 ,3 > y ;Array2D < int ,3 ,3 > z ;multiply (z ,x , y ); // error : struct Array2D < int , 3 , 3 >// has no member named ’ at ’58 / 99Специализация шаблона функцииБазовыесведенияОбобщённоепрограммированиеОбъявлениешаблоновПорождениекодаСпециализацияшаблоновПерегрузкаоперацийИсключенияСпециализация шаблона – это разработка отдельной версии порождаемого шаблоном кода для конкретного наборафактических параметров.Пусть имеется шаблон функции видаtemplate < формальные_параметры >тип имя (...){ ...
}Специализированная версия функции для конкретного набора фактических параметров записывается какtemplate <>тип имя < фактические_параметры >(...){ ... }Следует иметь в виду, что специализация шаблона функциине даёт особенных преимуществ над обычной перегрузкойфункций.59 / 99Пример: специализация шаблона функцииБазовыесведенияОбобщённоепрограммированиеОбъявлениешаблоновПорождениекодаСпециализацияшаблонов123456template < typename T > void do_swap ( T & a , T & b ){T c = a;a = b;b = c;}789Перегрузкаопераций10Исключения111213template <> void do_swap < int >( int & a , int & b ){a += b ;b = a-b;a = a-b;}1415161718192021int main (){int x = 10 , y = 20;do_swap (x , y ); // будет вызвана функция// в строчках 8..13return 0;}60 / 99Пример: перегрузка имеет больший приоритет,чем специализацияБазовыесведения12ОбобщённоепрограммированиеОбъявлениешаблоновПорождениекода3Специализацияшаблонов8Перегрузкаопераций456791011Исключенияtemplate < typename T >T t_max ( T a , T b ){cout << " 1 ␣ " ; return a > b ? a : b ;}template <>int t_max < int >( int a , int b ){cout << " 2 ␣ " ; return a > b ? a : b ;}12131415int t_max ( int a , int b ) {cout << " 3 ␣ " ; return a > b ? a : b ;}16171819202122int main (){int x = 10 , y = 20;cout << t_max (x , y ); // Вывод : 3 20return 0;}61 / 99Cпециализация шаблона классаСпециализированные версии шаблонов классов создаютсяаналогично специализации шаблонов функций.Например, рассмотрим шаблон класса, представляющегокортежи фиксированной длины:БазовыесведенияОбобщённоепрограммированиеОбъявлениешаблоновПорождениекодаСпециализацияшаблоновПерегрузкаоперацийИсключения123456789template < typename T , size_t N >class Tuple{private :T a [ N ];public :T get ( int i );void set ( int i , T x );};101112template < typename T , size_t N >T Tuple <T ,N >:: get ( int i ) { return a [ i ]; }131415template < typename T , size_t N >void Tuple <T ,N >:: set ( int i , T x ) { a [ i ] = x ; }62 / 99Пример: специализация шаблона классаБазовыесведения17ОбобщённоепрограммированиеОбъявлениешаблоновПорождениекода18Специализацияшаблонов23Перегрузкаопераций192021222425template <>class Tuple < bool , 8 >{private :unsigned char a ;public :bool get ( int i );void set ( int i , bool x );};26Исключения27282930bool Tuple < bool ,8 >:: get ( int i ){return ( a >> i ) & 1;}3132333435void Tuple < bool ,8 >:: set ( int i , bool x ){a |= ( unsigned char ) x << i ;}63 / 99Частичная специализация шаблона классаПри частичной специализации фиксируется только частьфактических параметров шаблона.
Например,БазовыесведенияОбобщённоепрограммированиеОбъявлениешаблоновПорождениекодаСпециализацияшаблонов3738394041Перегрузкаопераций42Исключения444345template < typename T >class Tuple <T ,1 >{private :T a;public :T get ( int i );void set ( int i , T x );};464748template < typename T >T Tuple <T ,1 >:: get ( int i ) { return a ; }495051template < typename T >void Tuple <T ,1 >:: set ( int i , T x ) { a = x ; }64 / 99Вычисления во время компиляцииСпециализация шаблонов позволяет заставить компиляторвыполнить некоторые вычисления во время компиляции.Например, можно попросить компилятор вычислить факториал числа:БазовыесведенияОбобщённоепрограммированиеОбъявлениешаблоновПорождениекодаСпециализацияшаблоновПерегрузкаопераций56789Исключенияtemplate < int N >struct Fact {static const unsigned long val =N * Fact <N -1 >:: val ;};1011121314template <>struct Fact <0 > {static const unsigned long val = 1;};151617181920int main (){cout << Fact <3 >:: val << ’\ n ’;return 0;}65 / 99Пример: возведение числа в степеньБазовыесведенияОбобщённоепрограммированиеОбъявлениешаблоновПорождениекодаСпециализацияшаблоновПерегрузкаопераций56789101112131415Исключенияtemplate < typename T , int N >struct Power {static T eval ( T x ) {if ( N % 2 == 0) {return Power <T , N /2 >:: eval ( x * x );}return x * Power <T ,N -1 >:: eval ( x );}};161718template < typename T >struct Power <T ,0 > {static T eval ( T x ) { return ( T )1; }};1920212223242526int main (){int x ;cin >> x ;cout << Power < int ,10 >:: eval ( x ) << ’\ n ’;return 0;}66 / 99Понятие перегрузки операцийБазовыесведенияОбобщённоепрограммированиеПерегрузкаоперацийВведениеПрисваиваниеБинарныеоперацииУнарные операцииОперация ()ИсключенияВообще, de facto практически в любом языке программирования операции перегружены.
Например, в языке Pascalсмысл операции «+» меняется в зависимости от типов операндов вплоть до того, что «сложение» строк означает ихконкатенацию.Язык C++ позволяет распространить принцип перегрузки на пользовательские типы данных, т.е. на классы. Приэтом, в отличие от языков, в которых пользователь можетсам составлять знаки операций и задавать их приоритет иассоциативность (например, ML или Haskell), ассортиментопераций и их характеристики в C++ жёстко заданы.Технически перегрузка операций в C++ реализована через определение функций со специальными именами вида«operator знак_операции», осуществляющих выполнениеопераций.67 / 99Ассортимент перегружаемых операцийБазовыесведенияОбобщённоепрограммированиеПерегрузкаоперацийВведениеПрисваиваниеБинарныеоперацииУнарные операцииОперация ()ИсключенияВ языке C++ допускается перегрузка следующего набораопераций:// унарные :++ -- - + ! ~ * & ( тип )// бинарные := += -= *= /= %= &= |= ^| < <= > >=+ - * / % & | ^ << >>== != > < >= <=&& ||[] -> - >* () ,Кроме того, допускается перегружать операции «new» и«delete».Перегруженные операции имеют те же приоритеты и ассоциативность, что и соответствующие операции над базовыми типами языка C++.Нельзя перегружать операции «.», «.*», «? :», «sizeof»,«dynamic_cast» и некоторые другие.68 / 99Перегрузка операции присваиванияБазовыесведенияОбобщённоепрограммированиеПерегрузкаоперацийВведениеПрисваиваниеБинарныеоперацииУнарные операцииОперация ()ИсключенияОперация присваивания для некоторого класса A перегружается путём объявления в классе метода, прототип которого выглядит какA & operator = ( const A & obj );Схема работы перегруженной операции присваивания:1.
проверить, не присваивается ли объект сам себе (еслитак, то перейти к пункту 5);2. освободить память, используемую внутри объекта;3. выделить память, в которую будет скопировано содержимое obj;4. выполнить копирование данных;5. вернуть *this.Вызов перегруженной операции присваивания можно выполнять двумя способами:a = b;// 1 - ый способa .
operator =( b ); // 2 - ой способ69 / 99Операция присваивания возвращает левоезначениеБазовыесведенияОбобщённоепрограммированиеПерегрузкаоперацийВведениеПрисваиваниеБинарныеоперацииУнарные операцииОперация ()ИсключенияФорма перегрузки операции присваивания в C++ наводитна мысль, что она возвращает левое значение, т.е. результату, возвращаемому операцией присваивания, можно чего-топрисвоить:A x, y, z;(x = y) = z;Этот код действительно работает. Более того, в отличие отязыка C, язык C++ допускает такое использование операции присваивания и для встроенных типов данных.
Например,int a = 2 , b = 3 , c = 4;(a = b) = c;Поэтому не стоит пытаться запретить такое поведение путём, например, возвращения константой ссылки:const A & operator = ( const A & obj );70 / 99Составные операции присваиванияБазовыесведенияОбобщённоепрограммированиеПерегрузкаоперацийВведениеПрисваиваниеБинарныеоперацииУнарные операцииОперация ()ИсключенияСоставные операции присваивания перегружаются по тойже схеме, что и обычная операция присваивания:A & operator += ( const A & obj );Как правило, в случае сложного внутреннего состояния объекта реализация перегруженной составной операции присваивания также должна предусматривать возможность присваивания объекта самому себе.Составные операции присваивания также возвращают левоезначение, обеспечивая работоспособность конструкций вида( x += y ) *= z ;71 / 99Перегрузка бинарных арифметических операцийБазовыесведенияОбобщённоепрограммированиеПерегрузкаоперацийВведениеПрисваиваниеБинарныеоперацииУнарные операцииОперация ()ИсключенияПрототип перегруженной бинарной арифметической операции может выглядеть какconst A & operator + ( const A & other ) const ;Отметим, что ключевое слово const в конце прототипа метода означает, что метод не меняет внутреннее состояниеобъекта, для которого он вызван.