140 likes | 276 Views
Лекция 11. Операторы. Виды операторов. Бинарный Запись : a @ b Интерпретация : a.operator @ ( b ) operator @ ( a, b ) Унарный префиксный Запись : @a Интерпретация : a.operator @ () operator @ ( a ) Унарный постфиксный Запись : a@ Интерпретация : a.operator @ ( int )
E N D
Лекция 11 Операторы
Виды операторов • Бинарный Запись: a @ bИнтерпретация:a.operator @ ( b ) operator @ ( a, b ) • Унарный префиксный Запись: @aИнтерпретация: a.operator @ () operator @ ( a ) • Унарный постфиксный Запись: a@ Интерпретация: a.operator @ (int) operator @ ( a, int ) • Тернарный Не перегружается
Перегружаемые операторы • Перегрузка возможна • Перегрузка запрещена
Правила перегрузки • Только допустимые операторы Невозможно создать новую лексему языка • Сохранение приоритетов Невозможно изменить приоритет оператора • Разрешение вызовов Аналогично разрешению вызовов при перегрузке функций
Определение в классах • Операторы с lvalue Операторные функции, требующие чтобы первым аргументом было lvalue (например: =, [], (), ->) обязаны быть нестатическими членами класса • Требование пользовательских типов Перегруженная операторная функция должна иметь либо один аргумент пользовательского типа, либо быть членом класса (кроме newи delete). Операторная функция, у которой первый аргумент принадлежит к встроенному типу, не может являться членом класса.
Объявление операторов • Операторы-методы • Операторы-функции struct Float { Float ( float f ) : f_ ( f ) {} Floatconst& operator += ( Float const & r ) { f_ += r.f_ ; return *this ; } friend Float operator+ ( Float const & , Float const & ); private : float f_ ; }; Float operator+ ( Float const & l, Float const & r ) { Float result ( l ); result += r ; return result ; }
Арифметические операторы • Объявляются вне класса Обычно арифметические и логические операторы для пользовательского типа определяются вне объявления этого типа.В случае необходимости операторные функции объявляются дружественными соответствующему классу. • Возвращают результат по значению Результат арифметических операторов – временный объект, поэтому семантика передачи не может быть адресной • Комбинации с базовыми типами Для бинарных операторов может быть три комбинации с базовым типом Float operator+ ( Float const & l, Float const & r ); Float operator+ ( Float const & l, float r ); Float operator+ ( float l, Float const & r );
Операторы присваивания • Являются членами класса Операторы присваивания в качестве первого аргумента требуютlvalue, поэтому всегда являются членами класса. • Возвращают измененный объект В обычной семантике присваивание возвращает свой первый операнд (сам объект). Во избежание неоднозначностей его принято отдавать по константной ссылке. Floata, b, c ; a = b = c = 7 ; // Все хорошо (a = b) = 9 ; // Ошибка, результат (a=b) – неизменяем struct Float { Float const & operator = ( float c ) { f_ = c ; return *this ; } float f_ ; };
Оператор приведения типа • Приведения пользовательских типов Пользовательский в стандартный Новый пользовательский в уже существующий struct Float { Float ( float f ) : f_ ( f ) {} operator float () const { return f_ ; } operator Double () const { return Double ( f_ ); } private : float f_ ; }; Float pi ( 3.1415926f ); float value = sin ( pi ); // Приведение типов
Оператор индексации • Семантика массива Доступ к элементам класса по некоторому индексу • Произвольный тип индексации Аргумент, по которому осуществляется выборка, может быть произвольного типа, в том числе и пользовательского. struct Array { Array ( intsz ) { af_ = newfloat[sz]; } ~Array () { delete[] af_ ; } floatoperator [] ( inti ) const { returnaf_[i]; } float& operator [] ( inti ) { returnaf_[i]; } private : float * af_ ; }; Array a ( 5 ); a[ 3 ] = 7 ;
Оператор вызова • Семантика функции Объект класса, у которого определен оператор (), приобретает семантику функции и называется функтором. Объект-функтор может быть исполнен в любой момент, таким же образом, как и обычная функция. • Произвольный набор аргументов Действуют обычные правила перегрузки struct Linear { Linear ( float a, float b ) : a_(a), b_(b) {} floatoperator ()( float x ) const { return a_ * x + b_ ; } private : float a_, b_ ; }; Linear lin ( 2, 1 ); // 2 * x + 1 ; float r = lin ( 7 );
Оператор разыменования • Всегда член класса Требует lvalueв качестве первого аргумента • Семантика указателя Позволяет обращаться к полям другого класса • Уникален Возвращаемый тип не участвует в перегрузке, поэтому оператор разыменования может быть только один (не считая constметода) struct X { float f_ ; }; structPtr { X * operator -> () { return &x_; } private : X x_ ; }; Ptr p ; p->x = 9 ; // (p.operator->())->x ;
Инкремент и декремент • Префиксная семантика Возвращается неконстантная ссылка на объект • Постфиксная семантика Возвращается объект по значению struct A { A& operator++ () { x_++ ; return *this ; } private : int x_ ; }; struct A { A operator++ (int) { A old ( *this ); ++*this; return old ; } private : int x_ ; };
Операторы newи delete • Могут быть глобальными и локальными • В классе неявно являются статическими • newможет иметь доп. параметры void * operatornew ( size_t bytes ); voidoperatordelete ( void * address ); voidoperatordelete ( void * address, size_t bytes ); struct Memory {void * operatornew ( size_t bytes ); void * operatornew[]( size_t bytes ); void * operatornew ( size_t bytes, const char * desc ); voidoperatordelete[]( void * address );voidoperatordelete ( void * address, size_t bytes );}; Memory * m1 = new Memory ; Memory * m2 = new (“Hello”) Memory ; delete m1 ; delete m2 ;