1 Переопределение операций Макаревич Л. Г.
2 Зачем нужна перегрузка операций? class Complex { double re; double im; public: Complex(double r=0, double i=0):re(r), im(i){} double getRe(){return re;} double getIm(){return im;} }; void main() { Complex c1(5,6); Complex c2(8,99); Complex c3; // c3 = c1 + c2; }
3 Что нельзя перегружать. – селектор члена структуры * - оператор доступа к члену по указателю :: - оператор разрешения видимости ?: - условный тернарный оператор
4 Различают: Бинарные Унарные Переопределяют: Функции-члены класса Внешние функции - операция, а w, x, y – объекты. эквивалентно y эквивалентно x (y) (x, y)
5 Перегруженные операции как функции-члены class Complex { double re; double im; public: Complex(double r=0, double i=0):re(r), im(i){} double getRe(){return re;} double getIm(){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 c1(5,6); Complex c2(8,99); Complex c3; c3 = c1 + c2; // c3 = c1.operator + ( c2); c3 = -c2; // c3 = c2.operator – (); }
6 Перегруженные операции как внешние функции class Complex { double re; double im; public: Complex(double r=0, double i=0):re(r), im(i){} double getRe(){return re;} double getIm(){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 & r1, const Complex & r2); friend Complex operator ! (const Complex & r1); }; Complex operator – (const Complex & r1, const Complex & r2) {Complex rez; rez.re = r1.re - r2.re; rez.im = r1.im - r2.im; return rez; } Complex operator ! (const Complex & r1) {Complex rez; rez.re = -r1.re; rez.im = r1.im; return rez; } void main() { Complex c1(5,6); Complex c2(8,99); Complex c3; c3 = c1 + c2; // c3 = c1.operator + ( c2); c3 = -c2; // c3 = c2.operator – (); c3 = c1 - c2; // c3 = operator - (c1, c2); c3 = !c2; // c3 = operator ! (c2); }
7 class Complex { double re; double im; public: Complex(double r=0, double i=0):re(r), im(i){} double getRe(){return re;} double getIm(){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 & r1, const Complex & r2); friend Complex operator ! (const Complex & r1); Complex operator + ( double d) { Complex rez = *this; rez.re = -rez.re + d; return rez; } }; void main() { Complex c1(5,6); Complex c2(8,99); Complex c3; c3 = c1 + c2; // c3 = c1.operator + ( c2); c3 = -c2; // c3 = c2.operator – (); c3 = c1 - c2; // c3 = operator - (c1, c2); c3 = !c2; // c3 = operator ! (c2); с3 = с2 + 10; с3 = 10 + c2; } Вопрос «на засыпку» friend Complex operator – (const double r1, const Complex & r2); Complex operator – (const double r1, const Complex & r2) { Complex rez = r2; rez.re = rez.re + d; return rez; }
8 Оператор присваивания Присваивание по умолчанию Присваивание по умолчанию Не наследуется Не наследуется Определяется как функция-член класса Определяется как функция-член класса 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; } }; void main() { String s1("abcdef"); String s2("1234"); String s3; s3 = s1; s2 = s2; s3 = s1 = s2; }
9 Вопрос «на засыпку» void main() { String s1("abcdef"); String s2("1234"); String s3; s3 = s1; s2 = s2; s3 = s1 = s2; String s4 = s1; } В чем разница?
10 Префиксные и постфиксные операторы 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 = ? }
11 Оператор индексирования Оператор бинарный a = b[10]; // a = b.operator[](10); //a = b[5][6]; - так нельзя Оператор бинарный a = b[10]; // a = b.operator[](10); //a = b[5][6]; - так нельзя Оператор – функция-член класса Оператор – функция-член класса Оператор индексирования ассоциируется с массивами Оператор индексирования ассоциируется с массивами 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; } char & operator[] (int i) { if (( i >= 0 ) && ( i < (int)len )) return str[i]; } }; void main() { String s1("abcdef"); String s2("1234"); String s3; s3 = s1; s2 = s2; s3 = s1 = s2; char a = s3[2]; s3[2] = 's'; }
12 class ArrString { const int max; char ** pstr; int cur; public: ArrString(int j):max(j),cur(0){pstr = new char *[max];} void add(char * toAdd) { if ( cur < max) pstr[cur++] = toAdd; } char * operator[](int i) { if ((i >= 0)&&(i < cur)) return pstr[i]; return NULL; } int operator[](char * toFind) { for ( int i = 0; i < cur; i++) if ( strcmp(pstr[i], toFind)) return i; return -1; } }; void main() { String s1("abcdef"); String s2("1234"); String s3; s3 = s1; s2 = s2; s3 = s1 = s2; char a = s3[2]; s3[2] = 's'; ArrString arr(5); arr.add("123"); arr.add("qqqqqqqqq"); arr.add("aaaaaa"); int i = arr["123"]; char* p = arr[2]; }
13 Оператор вызова функций Оператор – функция-член класса Оператор – функция-член класса Функция может перегружаться, различие – в сигнатуре функций Функция может перегружаться, различие – в сигнатуре функций class A { int i,j; public: тип возврата operator()(список параметров); }; A a1; a1(список фактических параметров); // a1.operator()(список фактических параметров);
14 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; len = s.len; str = new char[len + 1]; strcpy(str,s.str); return *this; } char& operator[] (int i) { if (( i >= 0 ) && ( i < (int)len )) return str[i]; } char & operator()(int i) { return str[i];} char * operator()(int i, int j) {return &str[i+j];} }; void main() { String s1("abcdef"); String s2("1234"); String s3; s3 = s1; s2 = s2; s3 = s1 = s2; char a = s3[2]; s3[2] = 's'; s3(2) = 'b'; char ch = s3(1,1); }
15 Переопределение операции -> Оператор – функция-член класса Оператор – функция-член класса Возвращает указатель на структуру или объект класса Возвращает указатель на структуру или объект класса class YPtr { Y*py; public: YPtr(const int a) { py = new Y; py->a = py->b = a; } Y * operator ->() { return py; } ~YPtr(){delete py;} }; int main() { YPtr y(66); y->a = 99;// ( y.operator ->())->a y->b = 77; return 0; }
16 Перегрузка new и delete Оператор new должен иметь следующий прототип: void * new(size_t size, …); #include Оператор new должен иметь следующий прототип: void * new(size_t size, …); #include Оператор new может перегружаться Оператор new может перегружаться Операция new всегда статическая функция Операция new всегда статическая функция Оператор delete должен иметь прототип: void delete(void * ) Оператор delete должен иметь прототип: void delete(void * ) Оператор delete не может перегружаться Оператор delete не может перегружаться Оператор delete – статическая функция Оператор delete – статическая функция
17 class Blanks { public: Blanks(){} void *operator new( size_t st, char chInit ); }; void *Blanks::operator new( size_t st, char chInit ) { void *pvTemp = malloc( st ); if( pvTemp != 0 ) memset( pvTemp, chInit, st ); return pvTemp; } int main() { Blanks *a5 = new( 0xa5 ) Blanks; return a5 != 0; }
18 #include using namespace std; class Stack2 { int top_num; public: void * operator new(size_t s, int sz = 100) { return new char[s + sz* sizeof (int)]; } Stack2(){top_num = 1;} void push(int i){*((int *)this + top_num++) = i;} int pop(){return *((int *)this + --top_num);} }; class Stack1 { int * pst; int size; int count; public: Stack1(int s=100):size(s){pst = new int [size]; count = 0;} ~Stack1(){ delete pst;} void push( int value) { if ( count < size ) pst[count++] = value; return; } int pop() { return pst[--count];} }; void main() { Stack1 st1; //Stack2 st2; - нельзя, почему? Stack2 * st2 = new ( 20) Stack2; st1.push(6); st1.push(7); st1.push(2); st1.push(66); st2->push(6); st2->push(7); st2->push(2); st2->push(66); cout
19 class A { int* s1,* s2,* s3; 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 * a1 = new(55) A; //… delete a1; }
20 class B { int i; public: int operator,(int k) { return i +k;} B(int _i){i = _i;} }; void main() { B b1(3); int k = (b1,8); }
21 Приведение типов С помощью конструктора С помощью конструктора С помощью оператора приведения типов С помощью оператора приведения типов
22 Приведение типов с помощью конструктора 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& b1){a = b1.b;} }; void main() { B bb(99); A aa = bb;}
23 Приведение типов с помощью операций приведения 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& b1){a = b1.b;} operator B(){B b1(a+99); return b1;} operator int(){ return 55*a;} }; void main() {B bb(99); A aa = bb; B x = aa; int k = aa; } operator тип (); operator тип (); Функция – член класса Функция – член класса Возвращает объект типа тип Возвращает объект типа тип
24 Указатели на элементы класса (методы) class Monstr { int health; int ammo; public: Monstr(int h, int a):health(h), ammo(a){} int get_health(){return health;} int get_ammo(){return ammo;} void f(int (Monstr::*pget)()) { (this->*pget)(); (*this.*pget)(); } }; void main() { Monstr Vasya; Monstr *p = new Monstr(2,100); Vasya.f(Monstr::get_health); int (Monstr::*pget)();// указатель на метод класса pget = &Monstr::get_health; Vasya.f(pget); int Vasin_health = (Vasya.*pget)(); int monstr_health = (p->*pget)(); } Нельзя определить указатель на статический метод класса Нельзя преобразовать указатель на метод к указателю на обычную функцию Указателю на метод можно присваивать адреса методов с определенным заголовком
25 Указатели на элементы класса (поля) class Monstr { public: int health; int ammo; public: Monstr(int h = 100, int a = 0):health(h), ammo(a){} int get_health(){return health;} int get_ammo(){return ammo;} void f(int (Monstr::*pget)()) { (this->*pget)(); (*this.*pget)(); } }; void main() { Monstr Vasya; Monstr *p = new Monstr(2,100); int (Monstr::*phealth) = &Monstr::health; cout health; ошибка cout *phealth; }