Лекция4. Перегрузка_операций_в_С++.ppt
- Количество слайдов: 24
Переопределение операций 1
Зачем нужна перегрузка операций? class Complex { double re; double im; public: Complex(double r=0, double i=0): re(r), im(i){} double get. Re(){return re; } double get. Im(){return im; } }; void main() { Complex c 1(5, 6); Complex c 2(8, 99); Complex c 3; // c 3 = c 1 + c 2; } 2
Что нельзя перегружать . – селектор члена структуры * - оператор доступа к члену по указателю : : - оператор разрешения видимости ? : - условный тернарный оператор sizeof – определение размера # - препроцессорные операции 3
Различают: • Бинарные • Унарные Переопределяют: • Функции-члены класса • Внешние функции Пусть @ - операция, а w, x, y – объекты. Тогда @W эквивалентно w. operator @() operator @(w) x @ y эквивалентно x operator @ (y) operator @ (x, y) 4
Перегруженные операции как функции-члены class Complex { double re; double im; public: Complex(double r=0, double i=0): re(r), im(i){} double get. Re(){return re; } double get. Im(){return im; } Complex operator + (const Complex & c) { Complex rez; rez. re = re + c. re; rez. im = im + c. im; return rez; } Complex operator – () const { Complex rez = *this; rez. re = -rez. re; return rez; } }; void main() { Complex c 1(5, 6); Complex c 2(8, 99); Complex c 3; c 3 = c 1 + c 2; // c 3 = c 1. operator + ( c 2); c 3 = -c 2; // c 3 = c 2. operator – (); } 5
Перегруженные операции как внешние функции Complex operator – (const Complex & r 1, const Complex & r 2) class Complex { Complex rez; { rez. re = r 1. re - r 2. re; double re; rez. im = r 1. im - r 2. im; double im; return rez; public: } Complex(double r=0, double i=0): re(r), im(i){} Complex operator ! (const Complex & r 1) double get. Re(){return re; } { Complex rez; double get. Im(){return im; } rez. re = -r 1. re; Complex operator + (const Complex & c) rez. im = r 1. im; { void main() return rez; Complex rez; { } rez. re = re + c. re; Complex c 1(5, 6); rez. im = im + c. im; Complex c 2(8, 99); return rez; Complex c 3; } c 3 = c 1 + c 2; Complex operator – () const // c 3 = c 1. operator + ( c 2); { c 3 = -c 2; Complex rez = *this; // c 3 = c 2. operator – (); rez. re = -rez. re; c 3 = c 1 - c 2; return rez; // c 3 = operator - (c 1, c 2); } c 3 = !c 2; friend Complex operator – (const Complex & r 1, const // c 3 = operator ! (c 2); Complex & r 2); } friend Complex operator ! (const Complex & r 1); 6 };
Вопрос «на засыпку» class Complex { double re; double im; public: Complex(double r=0, double i=0): re(r), im(i){} double get. Re(){return re; } double get. Im(){return im; } Complex operator + (const Complex & c) { Complex rez; rez. re = re + c. re; rez. im = im + c. im; return rez; } Complex operator – () const { Complex rez = *this; rez. re = -rez. re; return rez; } friend Complex operator – (const Complex & r 1, const Complex & r 2); friend Complex operator ! (const Complex & r 1); Complex operator + ( double d) { Complex rez = *this; rez. re = -rez. re + d; return rez; } }; void main() { Complex c 1(5, 6); Complex c 2(8, 99); Complex c 3; c 3 = c 1 + c 2; // c 3 = c 1. operator + ( c 2); c 3 = -c 2; // c 3 = c 2. operator – (); c 3 = c 1 - c 2; // c 3 = operator - (c 1, c 2); c 3 = !c 2; // c 3 = operator ! (c 2); с3 = с2 + 10; с3 = 10 + c 2; } friend Complex operator – (const double r 1, const Complex & r 2); Complex operator – (const double r 1, const Complex { Complex rez = r 2; rez. re = rez. re + d; return rez; } 7
Оператор присваивания Ø Присваивание по умолчанию Ø Не наследуется Ø Определяется как функция-член класса void main() { String s 1("abcdef"); String s 2("1234"); String s 3; s 3 = s 1; s 2 = s 2; s 3 = s 1 = s 2; } class String { char * str; int len; public: String() {str = NULL; len = 0; } String(char * s){len = strlen(s); str = new char[len + 1]; strcpy(str, s); } String(const String &s){len = s. len; str = new char[len + 1]; strcpy(str, s. str); } String & operator = (const String & s) { if ( this == &s) return *this; delete str; len = s. len; str = new char[len + 1]; strcpy(str, s. str); return *this; } }; 8
Вопрос «на засыпку» void main() { String s 1("abcdef"); String s 2("1234"); String s 3; s 3 = s 1; s 2 = s 2; s 3 = s 1 = s 2; String s 4 = s 1; } В чем разница? 9
Префиксные и постфиксные операторы class X { int value; public: X& operator ++() //префиксный { value++; return *this; } X operator ++(int) //постфиксный { X t = *this; value ++; return t; } }; void main() { X x; X y = x++; // y. value = ? X z = ++x; // z. value = ? } 10
Оператор индексирования Оператор бинарный a = b[10]; // a = b. operator[](10); //a = b[5][6]; - так нельзя Ø Оператор – функция-член класса Ø Оператор индексирования ассоциируется с массивами char & operator[] (int i) Ø { class String if (( i >= 0 ) && ( i < (int)len )) return str[i]; { char * str; } int len; }; void main() public: { String() String s 1("abcdef"); {str = NULL; len = 0; String s 2("1234"); } String s 3; String(char * s){len = strlen(s); str = new char[len + 1]; strcpy(str, s); } s 3 = s 1; String(const String &s){len = s. len; str = new char[len + 1]; s 2 = s 2; strcpy(str, s. str); } String & operator = (const String & s) s 3 = s 1 = s 2; { char a = s 3[2]; if ( this == &s) return *this; s 3[2] = 's'; delete str; len = s. len; str = new char[len + 1]; strcpy(str, s. str); return *this; } 11 }
class Arr. String { const int max; char ** pstr; int cur; public: Arr. String(int j): max(j), cur(0){pstr = new char *[max]; } void add(char * to. Add) void main() { if ( cur < max) pstr[cur++] = to. Add; { } String s 1("abcdef"); char * operator[](int i) String s 2("1234"); { if ((i >= 0)&&(i < cur)) return pstr[i]; return NULL; String s 3; } s 3 = s 1; int operator[](char * to. Find) s 2 = s 2; { s 3 = s 1 = s 2; for ( int i = 0; i < cur; i++) if ( strcmp(pstr[i], to. Find)) char a = s 3[2]; return i; s 3[2] = 's'; return -1; Arr. String arr(5); } }; arr. add("123"); arr. add("qqqqq"); arr. add("aaaaaa"); int i = arr["123"]; char* p = arr[2]; } 12
Оператор вызова функций Ø Оператор – функция-член класса Ø Функция может перегружаться, различие – в сигнатуре функций class A { int i, j; public: тип возврата operator()(список параметров); }; A a 1; a 1(список фактических параметров); // a 1. operator()(список фактических параметров); 13
class String { char * str; size_t len; public: String() {str = NULL; len = 0; } String(char * s){len = strlen(s); str = new char[len + 1]; strcpy(str, s); } String(const String &s){len = s. len; str = new char[len + 1]; strcpy(str, s. str); } String & operator = (const String & s) { if ( this == &s) return *this; delete str; void main() len = s. len; str = new char[len + 1]; strcpy(str, s. str); { return *this; String s 1("abcdef"); } String s 2("1234"); char& operator[] (int i) { String s 3; if (( i >= 0 ) && ( i < (int)len )) return str[i]; s 3 = s 1; } s 2 = s 2; char & operator()(int i) { return str[i]; } s 3 = s 1 = s 2; char * operator()(int i, int j) char a = s 3[2]; {return &str[i+j]; } s 3[2] = 's'; }; s 3(2) = 'b'; char *ch = s 3(1, 1); } 14
Переопределение операции -> Ø Оператор – функция-член класса Ø Возвращает указатель на структуру или объект класса int main() { YPtr y(66); y->a = 99; // (y. operator ->())->a y->b = 77; return 0; } class point{ public: int a, b; }; class YPtr { point *py; public: YPtr(const int a) { py = new point(); py->a = py->b = a; } point * operator ->() { return py; } ~YPtr(){delete py; } }; 15
Перегрузка new и delete Оператор new должен иметь следующий прототип: void * new(size_t size, …); #include
class Blanks { public: Blanks(){} void *operator new( size_t st, char ch. Init ); }; void *Blanks: : operator new( size_t st, char ch. Init ) { void *pv. Temp = malloc( st ); if( pv. Temp != 0 ) memset( pv. Temp, ch. Init, st ); return pv. Temp; } int main() { Blanks *a 5 = new( 0 xa 5 ) Blanks; return a 5 != 0; } 17
#include
class A { int* s 1, * s 2, * s 3; public: void * operator new(size_t s, size_t n) { return : : new int[ s+3*n ]; } void operator delete(void * p) { : : delete p; } }; void main() { A * a 1 = new(55) A; //… delete a 1; } 19
class B { int i; public: int operator , (int k) { return i +k; } B(int _i){i = _i; } }; void main() { B b 1(3); int k = (b 1, 8); } 20
Приведение типов Ø С помощью конструктора Ø С помощью оператора приведения типов 21
Приведение типов с помощью конструктора class A; class B { int b; public: B(int i){b = i; } friend class A; }; class A { int a; public: A(int i){a = i; } A(const B& b 1){a = b 1. b; } }; void main() { B bb(99); A aa = bb; } 22
Приведение типов с помощью операций приведения operator тип (); Ø Функция – член класса Ø Возвращает объект типа тип Ø class A; class B { int b; public: B(int i){b = i; } friend class A; }; class A { int a; public: A(int i){a = i; } A(const B& b 1){a = b 1. b; } operator B(){B b 1(a+99); return b 1; } operator int(){ return 55*a; } }; void main() { B bb(99); A aa = bb; B x = aa; int k = aa; } 23
Правила перегрузки типов Ø Ø Ø Ø Вводить собственные обозначения для операций, не совпадающие со стандартными операциями языка С++, нельзя. Каждая операция, заданная в языке, имеет определенное число операндов, свой приоритет и ассоциативность. Все эти правила, установленные для операций в языке, сохраняются и для ее перегрузки, т. е. изменить их нельзя. Любая унарная операция определяется двумя способами: либо как компонентная функция без параметров, либо как глобальная (возможно дружественная) функция с одним параметром. Выражение z означает в первом случае вызов z. operator (), во втором - вызов operator (z). Любая бинарная операция определяется также двумя способами: либо как компонентная функция с одним параметром, либо как глобальная (возможно дружественная) функция с двумя параметрами. В первом случае x y означает вызов x. operator (y), во втором – вызов operator (x, y). Перегруженная операция не может иметь аргументы (операнды), заданные по умолчанию. В языке С++ установлена идентичность некоторых операций, например, ++z – это тоже, что и z+=1. Эта идентичность теряется для перегруженных операций. Функцию operator можно вызвать по ее имени, например, z=operator*(x, y) или z=x. operator*(y). В первом случае вызывается глобальная функция, во втором – компонентная функция класса Х, и z – это объект класса Х. Однако, чаще всего функция operator вызывается косвенно, например, z=x*y За исключением перегрузки операций new и delete функция operator должна быть либо нестатической компонентной функцией, либо иметь как минимум один аргумент (операнд) типа “класс” или “ссылка на класс” (если это глобальная функция). Операции ‘=’, ‘[]’, ‘–>’, () можно перегружать только с помощью нестатической компонентной функции operator. Это гарантирует, что первыми операндами будут леводопустимые выражения. Перегрузка операций ‘++’ и ‘--‘, записываемых после операнда (z++, z--), отличается добавлением в функцию operator фиктивного параметра int, который используется только как признак отличия операций z++ и z-- от операций ++z и --z. Глобальные операции new можно перегрузить и в общем случае они могут не иметь аргументов (операндов) типа “класс”. В результате разрешается иметь несколько глобальных операций new, которые различаются путем изменения числа и (или) типов аргументов. Глобальные операции delete не могут быть перегружены. Их можно перегрузить только по отношению к классу. Для правильного освобождения динамической памяти под базовый и производный объекты следует использовать виртуальный деструктор. Если для класса Х операция “=” не была перегружена явно и x и y - это объекты класса Х, то выражение x=y задает по умолчанию побайтовое копирование данных объекта y в данные объекта x. 24


