КАТЕГОРИИ: Архитектура-(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) операцій
Хотілося б вирахувати суму до сплати як
total = chicken + wine + pie;
Для цього потрібна позакласна
float operator+( const MenuItem& item1, const MenuItem& item2) { return(item1.getPrice() + item2.getPrice()); }
або класна float MenuItem:: operator+(const MenuItem& item) { return(GetPrice() + item.GetPrice()); }
Спробуємо розібратися, скільки довизначень оператора додавання необхідно тепер. Зокрема ясно, як буде опрацьовано вираз
chicken + houseWine
але неясно, що робити з виразом
chicken + houseWine + applePie
Дійсно, групуючи операції зліва направо, одержимо вираз типу
<float> + <MenuItem>,
справа наліво: <MenuItem> + <float>,
жоден з яких не відповідає сигнатурі довизначення <MenuItem>+<MenuItem>.
Насправді можливі всі чотири випадки:
MenuItem MenuItem MenuItem float float MenuItem float float
А тому повне визначення оператора додавання складатиметься з чотирьох частин:
class MenuItem { private: float price; string name; public: MenuItem(float, string); MenuItem(float, char[]); MenuItem(const MenuItem&); float getPrice(); float operator+(const MenuItem&); float operator+(float); }; float MenuItem::operator+(const MenuItem& item) { return(getPrice() + item.getPrice()); } float MenuItem::operator+(float subtotal) { return(GetPrice() + subtotal); }
плюс ще одна утиліта класу
float operator+(float subtotal,const MenuItem& item) { return(subtotal + item.getPrice()); }
плюс стандартна операція додавання дійсних чисел.
Другий варіант полягає у визначенні перетворення MenuItem в дійсне число
MenuItem::operator float(){return price;}
Перетворення типів обходиться меншою кількістю функцій, але вимагає більшої кількості викликів.
Асоціативність операцій може призвести до великих втрат пам'яті. Розглянемо приклад матриць
class Matrix { static const int size; double **M; public: //обчислення добутку з копіюванням результату
Matrix operator*(const Matrix&); };
реалізація множення:
const int Matrix::size=10; Matrix Matrix::operator+(const Matrix& b) { Matrix res; for(int i=0; i<size; i++) for(int j=0; j<size; j++) { double s=0; for(int k=0; k<size; k++) s+=this->M[i][k]*b.M[k][j]; res.M[i][j]=s; } return res; }
Як буде виконуватися множення?
Matrix A, B, C, D; D = (A * B) * C;
Чи не буде великих втрат ефективності при копіюванні проміжного результату (A*B) до тимчасового об'єкту this, що активізує друге множення.
_this = A*B; D= _this*C;
Було б ефективніше утримати проміжний результат на місці безпоседньо до його використання в наступному множенні. Спробуємо так
class Matrix { static const int size; double **M; public: //обчислення добутку з копіюванням результату Matrix& operator*(const Matrix&); }; Matrix& Matrix::operator*(const Matrix& b) { Matrix *res = new Matrix; for(int i=0; i<size; i++) for(int j=0; j<size; j++) { double s=0; for(int k=0; k<size; k++) s+=this->M[i][k]*b.M[k][j]; res->M[i][j]=s; } return *res; }
Тепер з'явилася інша проблема: ніхто більше не відповідає за знищення проміжного результату. Раніше об'єкт res знищувався при виході із функції. Проблема ефективності іменованого результату так і залишається проблемою. З точки зору ефективності доцільніше використовувати функції з модифікованими параметрами, а не операції
void mult(const Matrix& a, const Matrix& b, Matrix& res);
Правда тепер стане неможливим запис матричних виразів, а також можливі інші несподіванки, наприклад, при виклику
mult(A, B, A);
або навіть
mult(A, A, A);
Це відома проблема кратних параметрів: якщо результат формується в одному з параметрів, то параметр може спотворитися раніше, ніж його повністю використають.
Клас Matrix вимагає також довизначення присвоєння
Matrix& operator=(const Matrix&);
яке зводиться до поелементного копіювання двох масивів, розмірності яких співпадають.
Matrix& Matrix::operator=(const Matrix& b) { for(int i=0; i<size; i++) for(int j=0; j<size; j++) M[i][j]=b.M[i][j]; return *this; }
Ось трохи складніший варіант
class string { private: char *s; short stringLength; public: string(); string(char *thestring); ~string(); void displayAddress(); string& operator=(const string &fromstring); };
Тепер розміри об'єктів у лівій і правій частині присвоєння різні
string::string() { stringLength = 2; s = new char[ stringLength + 1 ]; strcpy(s,"NN"); } string::string(char *thestring) { stringLength = strlen(thestring); s = new char[ stringLength + 1 ]; strcpy(s, thestring); } string::~string() { delete [] s; } void string::displayAddress() { cout<<s<<" at address: "<<(unsigned long)s<<"\n"; } string& string::operator=(const string &fromstring) { delete [] s; stringLength = fromstring.stringLength; s = new char[ stringLength + 1 ]; strcpy(s, fromstring.s); return *this; }
Ось ілюстрація того, як використовуватиметься пам’ять int main() { string theSwiss("Niklaus Wirth, TFH Zurich"); string theDutchman("Edsger Wybe Dijkstra, \ University of Texas at Austin & \ Burroughs Corporation"); string anAmerican; string aEuropean;
theSwiss.displayAddress(); theDutchman.displayAddress(); anAmerican.displayAddress(); aEuropean.displayAddress();
cout << "-----\n"; aEuropean = theSwiss; aEuropean.displayAddress();
cout <<"-----\n"; anAmerican = aEuropean = theDutchman; anAmerican.displayAddress(); aEuropean.displayAddress(); return 0; }
Дата добавления: 2014-01-06; Просмотров: 181; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |