Студопедия

КАТЕГОРИИ:


Архитектура-(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; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.023 сек.