360 likes | 629 Views
Предефиниране на операции. В C++ не могат да се дефинират нови оператори, но всеки съществуващ едноаргументен или двуаргументен оператор с изключение на :: , ?: , . , може да бъде предефиниран от програмиста, стига поне един операнд на оператора да е обект на някакъв клас .
E N D
Предефиниране на операции • В C++ не могат да се дефинират нови оператори, но всеки съществуващ едноаргументен или двуаргументен оператор с изключение на ::, ?:, ., може да бъде предефиниран от програмиста, стига поне един операнд на оператора да е обект на някакъв клас. • Например, възможно е да се предефинират операторите +, -, * и /, така че да могат да събират, изваждат, умножават и делят рационални числа. Тогава вместо sum(p, q), sub(p, q), mult(p, q) и quot(p, q) ще можем да пишем p+q, p-q, p*q и p/q, което е много по-удобно. • Предефинирането се осъществява с т. нар. операторни функции.
Предефиниране на операции • Механизмът на предефиниране дава възможност за интерпретация на класовете като нови типове данни. • Ако aи b са два обекта от даден клас, то предефинирането на операция +позволява а+b да има смисъл. • Операцията може да се предефинира, ако в нея участва поне един обект от някакъв клас. Общ вид на операторна функция резултат_обект operatorоперация(параметри); или void за резултат
Предефиниране на операции • Предефиниране с използване на независима приятелска функция • Предефиниране с използване на член - функция
Предефиниране на операции • Предефиниране с използване на независима приятелска функция Общ вид за предефиниране class A { //член-данни public: //декларации на член-функции friend A operatorоперация(A x,A y); }; A operatorоперация(A x,A y) { //Тяло на приятелската функция } декларация на приятелска функция дефиниция на приятелска функция
Предефиниране на операции • Предефиниране с използване на независима приятелска функция – пример за събиране на две рационални числа Декларация на клас рационално число #include <iostream.h> 1/3 class rac { private: int numer; int denom; public: rac(int=0, int=1); void read(); void print() const; friend rac operator+(rac const &, rac const &); }; rac::rac(int a, int b) {numer = a; denom = b; cout << "construct! \n"; } Декларация на приятелска функцияза предефиниране на + Дефиниция на конструктор
Предефиниране на операции • Предефиниране с използване на независима приятелска функция – пример за събиране на две рационални числа Дефиниция на функцияза въвеждане на обект void rac::read() 2/3 { cout << "numer: "; cin >> numer; do { cout << "denom: "; cin >> denom; } while (denom == 0); } void rac::print() const { cout<<numer<<"/"<<denom<<endl; } rac operator+(rac const & r1, rac const & r2) { rac r(r1.numer*r2.denom + r2.numer*r1.denom, r1.denom*r2.denom); return r; } Дефиниция на функцияза извеждане на обект Дефиниция на приятелска функцияза предефиниране на +
Предефиниране на операции • Предефиниране с използване на независима приятелска функция – пример за събиране на две рационални числа c = a + b; се интерпретира като c=operator+(a,b); void main() 3/3 {rac a(1,3), b(2,5); a.print(); b.print(); rac c; c=a+b; c.print(); c=a+b+c; c.print(); (a+b+c).print(); } construct construct 1/5 2/5 construct construct 11/15 construct construct 330/225 construct construct 7425/3375
Предефиниране на операции • Предефиниране с използване на член - функция Общ вид за предефиниране class A { //член-данни public: //декларации на член-функции A operatorоперация(A x); }; A А::operatorоперация(A x) { //Тяло на член-функция за предефиниране } декларация на член- функция за предефиниране дефиниция на член- функция за предефиниране
Предефиниране на операции • Предефиниране с използване на член – функция • Правило: Първият аргумент на член-функцията трябва да е обект на класа и при дефинирането на операторната функция не се задава като параметър. Ако това не е така, операцията не може да се предефинира като член-функция.
Предефиниране на операции • Предефиниране с използване на член – функция примерза събиране на две рационални числа #include <iostream.h> 1/3 class rac {private: int numer; int denom; public: rac(int=0, int=1); void read(); void print() const; rac operator+(rac const &) const; }; rac::rac(int a, int b) {numer = a; denom = b; cout << "construct! \n"; } Декларация на клас рационално число Декларация на член функцияза предефиниране на + първи операнд се получава неявно от обекта, извикал функцията Дефиниция на конструктор
Предефиниране на операции • Предефиниране с използване на член – функция примерза събиране на две рационални числа void rac::read() 2/3 { cout << "numer: "; cin >> numer; do { cout << "denom: "; cin >> denom; } while (denom == 0); } void rac::print() const { cout<<numer<<"/"<<denom<<endl; } rac rac::operator+(rac const & r1) const {rac r(numer*r1.denom + r1.numer*denom, denom*r1.denom); return r; } Дефиниция на функцияза въвеждане на обект Дефиниция на функцияза извеждане на обект Дефиниция на член функцияза предефиниране на +
Предефиниране на операции • Предефиниране с използване на член – функция примерза събиране на две рационални числа void main() 3/3 {rac a(1,3), b(2,5); a.print(); b.print(); rac c; c=a+b; c.print(); c=a+b+c; c.print(); (a+b+c).print(); } c = a + b; се интерпретира като c=a.operator+(b); construct construct 1/5 2/5 construct construct 11/15 construct construct 330/225 construct construct 7425/3375
Предефиниране на операции • За двата разгледани примера на предефиниране предаването на параметри е чрез псевдоним (т.е. по адрес), но връщането на резултат е по стойност (т.е. извършва се копиране). • За обекти с по-голяма дължина е препоръчително използване на псевдоними, както при предаване на параметри, така и при връщане на резултат. Декалрацияна приятелска функция friend point & operator + (point &a , point &b); . . . point & operator + (point &a); Декларация на член - функция friend point & operator + (const point &a , const point &b); . . . point & operator + (const point &a); За да не се променят параметрите
Предефиниране на операции • Ако първият операнд в операцията е от базов тип, операцията не може да се предефинира с член-функция. • Предефинираните операции запазват броя на аргументите си.
Предефиниране на операции Пример със съставно присвояване class test { int a,b; . . . void operator *=(test); void out() { cout << a<<“,”<<b<<“\n”; } }; void test :: operator *=(test x) test &test :: operator*=(test x) { a*=x.a; b*=x.b; }{ a*=x.a; b*=x.b; return *this; } void main() { test p; p*=5; p.out(); (p*=5).out(); } Или параметър (int x) За да няма грешка грешка – не връща резултат
Предефиниране на операции • Пример за изчисляване на изрази: • 1) ob1+=10; • 2) ob3=10*++ob2; • 3) 5*оb3++ Където ob1,ob2,ob3 са обекти на клас правоъгълник. Операциите ++ (префикснаи постфиксна) и += да се предефинират чрез член-функции, а * - чрез приятелска функция.
Предефиниране на операции Пример за изчисляване на изрази #include <iostream.h> 1/3 class rec { int w,l; public: rec(int a=0,int b=0) { w=a; l=b; } void out() { cout<<”правоъгълник:”<<w<<" "<<l<<"\n"; } rec &operator++() {w++; l++; return *this; } rec operator++(int n) { rec p=*this; w++; l++; return p; } предефиниране на ++ (префиксна) предефиниране на ++ (постфиксна)
Предефиниране на операции Пример за изчисляване на изрази Декларация на член – функция за предефиниране на += void operator+=(int a); 2/3 friend rec &operator*(int a,const rec &x); }; Декларация на приятелска функция за предефиниране на *
Предефиниране на операции Пример за изчисляване на изрази void rec::operator+=(int a) 3/3 { w+=a; l+=a; } rec &operator*(int a,const rec &x) { rec t; rec &p=t; t.w=x.w*a; t.l=x.l*a; return p; } void main() {rec ob1(1,2),ob2(5,6),ob3; ob1+=10; ob1.out(); ob3=10*++ob2; ob3.out(); (5*ob3++).out(); ob3.out(); } Дефиниция на член – функция за предефиниране на += Дефиниция на приятелска функция за предефиниране на * правоъгълник:11 12 правоъгълник:60 70 правоъгълник:300350 правоъгълник:61 71
Предефиниране на операции Предефиниране на операция присвояване (=) • Операцията може да се предефинира само с член – функция. • За обекти, които нямат член-данни, указващи към динамична зона може да се използва операцията присвояване по подразбиране. • За обекти с член – данни, указващи към динамична памет е задължително включване в класа на операторна член-функция за предефиниране.
Предефиниране на операции Предефиниране на операция присвояване (=) • За два обекта, дефинирани като: example a(5), b(3); • От прилагане на присвояване b=a; (виж Фиг. 1) следва: • преди присвояването съществуват два обекта (с техните динамични части, сочени от указател adr); • След присвояването (посимволно копиране), динамичната част на обекта b не се указва повече от b (указател adrна b сочи там, където и указателя adrна a). class example { int n; int *adr; public: ……..... }; Ако е дефиниран клас example с указател към динамична зона
Фиг. 1Фиг. 2 Предефиниране на операции операцията присвояване се предефинира (Фиг. 2). Предефиниране на операция присвояване (=)
Предефиниране на операции Предефиниране на операция присвояване (=) • Алгоритъм за предефиниране на операцията присвояване. • Ако a и bуказателите сочат един и същи обект, не се извършва действие. • Ако aи b указателите са различни, то: • Освобождава се динамичната зона, сочена от указателя на b; • Създава се нова динамична зона с размер, определен от броя елементи на а; • Копира се динамичната зона на а в новосъздадената.
Предефиниране на операции Предефиниране на операция присвояване (=) #include <iostream.h> 1/3 class vect { int nbr; int *adr; public: vect(int ); ~vect(); vect &operator=(const vect &); }; vect::vect(int n) { adr=new int[nbr=n]; for(int i=0;i<nbr;i++) adr[i]=0; } vect::~vect() { delete adr; } Резултат – псевдоним (позволява многократно (верижно) присвояване) Резултат – обект (само просто присвояване) Декларация на операторна функция за присвояване
Предефиниране на операции Предефиниране на операция присвояване (=) vect& vect::operator =(const vect &v)2/3 { if(this!=&v) { cout<<”изтриване на динамичен вектор\n”; delete adr; adr =new int[nbr =v.nbr]; for(int i=0;i<nbr;i++) adr[i]=v.adr[i]; } else cout<<”не се извършва действие\n”; return *this; }; Дефиниция на операторна функция за присвояване
Предефиниране на операции Предефиниране на операция присвояване (=) void main() 3/3 { vect a(5),b(3),c(4); cout<<”присвояване a=b\n”; a=b; cout<<”присвояване c=c\n”; c=c; cout<<”присвояване a=b=c\n”; a=b=c; } присвояване a=b изтриване на динамичен вектор присвояване с = с не се извършва действие присвояване a=b = с изтриване на динамичен вектор изтриване на динамичен вектор
Предефиниране на операции Предефиниране на операция присвояване (=) • Операторната функция за присвояване извършва аналогични действия на тези на копиращия конструктор. • Рaзликата е, че тя извършва тези действия върху съществуващ обект, а не върху токущо създаден. • Това налага предварително да бъде освободена динамичната памет, отделена за обекта.
Предефиниране на операции Предефиниране на операция присвояване (=) • Копиращият конструктор (или т. нар. Конструктор за присвояване), операторна функция за присвояване и деструктора се наричат “голямата тройка” или “канонична форма на класа”. • Те са задължителни при класове, използващи динамичната памет.
Предефиниране на операции Предефиниране на операция за достъп [ ] • Действията на операцията []задостъп до елемент от масив могат да се имитират с две член-функции, включени в класа. • Член – функция за въвеждане на стойност на дадена позиция pos • Член – функция за намиране на стойност от дадена позиция pos Въвежда 10 на позиция 0 в обекта а void range(int value, int pos); //a.range(10, 0); Извежда стойност от позиция 3 на обекта а int find(int pos); //cout << a.find(3);
Предефиниране на операции Предефиниране на операция за достъп [ ] • Цел на предефинирането: a[i]да се използва като лява страна при присвояване. • Операцията []дава възможност за достъп до елемент на масив, намиращ се на позиция iот динамичната зона на обект от зададен клас. • Връщаната от операторната функция стойност трябва да се предава чрез псевдоним с цел операцията да се използва от лявата страна на оператор за присвояване. • Параметър на операторната функция е позицията i.
Предефиниране на операции Предефиниране на операция за достъп [ ] #include <iostream.h> #define MAX 10 class vect { int nbr; int *adr; public: vect(); vect(int ); ~vect(); int & operator[ ](int); }; vect::vect() { adr= new int[nbr = MAX]; for(int i=0;i<MAX;i++) adr[i]=0; } Декларация на операторна функция [ ] Дефиниция на конструктор за създаване на временен обект
Предефиниране на операции Предефиниране на операция за достъп [ ] vect::vect(int n) { adr = new int[nbr = n]; for(int i=0;i<nbr;i++) { cout<<"adr["<<i<<"]="; cin>>adr[i]; } } vect::~vect() { delete adr; } int & vect::operator[ ](int i) { return adr[i]; } Дефиниция на конструктор Дефиниция на операторна функция [ ]
Предефиниране на операции Предефиниране на операция за достъп [ ] void main() { int i,n,s; do{ cout<<“въведи брой елементи:"; cin>>n; } while(n<1||n>MAX); vect a(n),b; for(i=0,s=0;i<n;i++) { b[i]=a[i]; s+=a[i]; } b[i]=s; for(i=0;i<n+1;i++) cout<<b[i]<<" "; } въведи брой елементи:3 adr[0]=22 adr[0]=33 adr[0]=44 22 33 44 99
Предефиниране на операции Предефиниране на операция за достъп [ ] • Вторият операнд в операцията би могъл да се защити от промяна чрез: • За да се използва за константни обекти, член-функцията трябва да е от тип const. • Това налага предефиниране от вида: int &operator [ ](const int); int vect :: operator [ ]( int i) const//дефинира се втора{ return adr[ i ]; }//операторна функция в класа Резултатът не е псевдоним, т.е обекта само се консултира без да се модифицира