КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Також можливе довизначення багатьох інших операційДовизначення (overloading) операцій Довизначення (overloading) операцій: арифметичні операції (бінарні, унарні, суміщені з присвоєнням), оператори управління пам'яттю, оператор виклику функції, оператор доступу до елементу масиву, оператор доступу за указником, оператор присвоєння,
Визначаючи за допомогою класу новий тип, ми вбудовуємо його в наявне середовище із своєю системою позначень і понять. Вбудовування це стане найбільш природним і адекватним, якщо ми збережемо значення вже наявних позначень, довизначивши та розширивши їх на нові об'єкти. Ось типова схема визначення класу
Class T {
//Мінімальний набір: //конструктор T(t,…,s); //конструктор копіювання T(const T&); //присвоєння глибоким копіюванням T& operator=(const T&); //деструктор ~T();
//Можливі операції: //бінарні арифметичні операції T operator?(const T&) const; //вони ж, сполучені з присвоєнням T& operator?=(const T&); //приведення типу T до типу S operator S();
//Особливості реалізації: //інфіксного декременту (звичайний спосіб) T operator++(); //постфіксного інкременту (фіктивний параметр) T operator++(int);
//Можливі непорозуміння: //обчислення адреси T* operator&() const; //кон’юнкція T operator&(const T&);
}
З мінімальним набором засобів у визначеному класі ми вже певною мірою знайомилися. Присвоєння потребує довизначення лише при необхідності глибокого копіювання, оскільки поверхневе копіювання передвизначене для кожного класу. Присвоєння, суміщене з операціями, потребує спеціального довизначення. Розглянемо арифметичні операції. Для цього визначимо дуже спрощений клас комплексних чисел
class complex { double _re, _im; public: complex (double r=0,double i=0):_re(r),_im(i){}; complex (const complex& c):_re(c._re),_im(c._im){}; complex operator+ (const complex&) const; complex& operator+= (const complex&); double re() const {return _re;} double im() const {return _im;} };
Проаналізуємо його. Конструктор має замовчування: complex z; надасть об'єкту z значення 0; complex z1(1); створить об'єкт з нульовою уявною частиною. Деструктор не потрібен, довизначення присвоєння теж.
Обмежимося поки що однією арифметичною операцією додавання. Цілком очевидно, чого варто сподіватися після виконання наступного фрагменту програми
complex u(1,1), v(2, 2),w;
w=u+v;
Трохи менш зрозумілим буде інший фрагмент
complex u(1,1), w;
w=u+1;
очевидно, що очікується збільшення дійсної частини на 1. Залишилося лише зрозуміти, як це відбувається. Для цього помітимо, що конструктор комплексного числа задає, крім всього іншого, перетворення дійсного числа в комплексне, наприклад, complex(1) перетворює дійсну одиницю на комплексне число, дійсна частина якого одиниця. Оскільки операції додавання з сигнатурою (complex, double) немає, відбувається підвищення типу дійсного до комплексного. Насправді присвоєння w=u+1; виконається як w=u+complex(1). Тобто щось на зразок
complex * tmp = new complex(1);
w = u+*tmp;
Якби ж ми доповнили б інтерфейс функцією
complex operator+ (double) const;
була б викликана вона і додатковий об'єкт не створювався б.
Те ж саме стосується оператора додавання з присвоєнням
complex u(1,1);
u+=1;
Реалізації операцій досить очевидні
complex& complex::operator+= (double a) { _re += a; return *this; } complex complex:: operator+ (double a)const { complex res = *this; return res+=a; }
Залишилася лише одна проблема, викликана бажанням зберегти комутативність операції додавання
complex u(1,1), w;
w=1+u;
присвоєння з явним конструктором проходить без проблем
w = complex(1)+u;
Неявне перетворення типів, можливе для другого аргументу, для першого виявилося неможливим. Чому? Відповідь зрозуміла. Як ми пам'ятаємо, класна функція, додатково до своїх параметрів містить ще указник на поточний об'єкт this, з яким цей метод безпосередньо працює. В нашому випадку цього об'єкту немає, його роль мусив би відігравати тимчасовий об'єкт, а це було б не зовсім коректно, оскільки об'єкт, що активізує метод, повинен жити довше, ніж період активності методу (тимчасові об'єкти ліквідуються при виході із функції)
complex * tmp = new complex(1); w = tmp + u;
Прирівняти в правах перший параметр з другим можна, винісши додавання за межі класу
complex operator+(const complex& a, const complex& b) { complex res=a; return res+=b; }
Тепер при необхідності виконати перетворення першого параметру викликатиметься не класна функція додавання, а утиліта класу.
Ще дві корисні утиліти:
complex operator==(const complex& a, const complex& b) { return (a.re()==b.re()) && (a.im()==b.im()); } ostream& operator<<(ostream &os, const complex& a) { os<<"re="<<a.re()<<" im="<<a.im()<<endl; return os; }
Детальніше про ввід-вивід у наступному підрозділі. Перейдемо тепер до множення комплексних чисел. Як відомо, множення простіше виконується над комплексними числами у тригонометричній формі. Визначимо новий клас
class Tcomplex { friend class complex; double _rho, _phi; public: Tcomplex (double r=0,double a=0): _rho(r),_phi(a){}; operator complex (); Tcomplex operator*(const Tcomplex&) const; Tcomplex operator*=(const Tcomplex&); double rho() const { return _rho;} double phi() const { return _phi; } };
Все, що тут написано, є очевидним аналогом класу комплексних чисел у алгебраїчній формі, крім оператора complex() перетворення тригонометричного комплексного числа в алгебраїчне. Ось його реалізація
Tcomplex::operator complex() { complex res(_rho*cos(_phi),_rho*sin(_phi)); return res; }
Аналогічним перетворенням можна поповнити клас комплексних чисел
Tcomplex::operator complex() { complex res(_rho*cos(_phi),_rho*sin(_phi)); return res; }
додавши його оголошення також до інтерфейсу. Тепер можливі змішані вирази з комплексних чисел. Для додавання тригонометричні будуть перетворюватися в алгебраїчну форму, для множення — навпаки.
class complex { double _re, _im; public: complex (double r=0,double i=0):_re(r),_im(i){}; complex (const complex& c):_re(c._re),_im(c._im){}; complex operator+ (const complex&) const; complex& operator+= (const complex&); double re() const {return _re;} double im() const {return _im;} operator Tcomplex(); bool operator!= (const complex& a) {return!(*this==a);} complex operator- (const complex&) const; complex& operator-= (const complex&); };
Пам'ятаємо, що перетворення типів чи довизначення функцій можуть бути альтернативою одне іншому. Яку з них обирати, залежить від додаткових вимог до задачі.
Тепер розглянемо нечисловий приклад.
class MenuItem { private: float price; string name; public: MenuItem(float, string); MenuItem(float, char[]); MenuItem(const MenuItem&); float getPrice(); };
Припустимо, що було зроблено замовлення:
MenuItem chicken(8.99, ”Київські котлети”); MenuItem wine(2.99, ”Каберне”); MenuItem pie(5.98,”Київський торт”); float total;
Дата добавления: 2014-01-06; Просмотров: 240; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |