Long operator – (string a,string b)

{return(atol(a.value) – atol(b.value));}

Перепишемо приклад, щоб перевантажені операції були членами класу:

class String {

private:

char value[100];

public:

String(){value [0]=0;}

String (const char*s);

long GetValue(void){return atol(value);}

long operator+(String b);

long operator – (String a);};

Main()

{String a="1234";

String b="4321";

cout<<"\na+b+6="<<(a+b+6);

cout<<"\na-b+10="<<(a-b+10)<<'\n';

return 0;}

String::String(const char*s)

{strcpy(value,s);

}

long String::operator+(String b)

{return(atol(value)+atol(b.value));}

Long String::operator – (String a)

{return(atol(a.value) – atol(value));}

Як видно з наведених прикладів, для будь-якої перевантаженої бінарної операції @ вираз aa @ bb інтерпретується як operator @ (aa,bb) чи aa. operator @ (bb) залежно від того, як визначена дана операція (функція-член чи функція-друг). Звідси бачимо, що перевантажена функція-член не може мати перший параметр-елемент основного типу. Адже 2 @ aa інтерпретується як 2.operator @ (aa), що не допускається.

Аналогічно для будь-якої унарної операції @ оператор aa@ чи @aa інтерпретується відповідно як operator @(aa) чи aa. operator @ ().

Перетворення типів

Програміст має сам подбати про перетворення типів при роботі з різнотипними даними, де використовуються його власні типи даних. Операції перетворення типів за умовчанням при роботі з типами користувача зазвичай не працюють. Виняток становить так зване неявне перетворення типів, про яке буде сказано далі. Для забезпечення роботи з різнотипними даними існує кілька підходів:

1. Використання перевантажених функцій з різними типами параметрів:

friend complex operator+(complex,complex);

friend complex operator+(complex,double);

………………..

complex b(2,2),c(3,3);

b=c+20+b;

2. Використання конструкторів, які виконують відповідні перетворення типів. Мається на увазі виклик відповідних конструкторів у ситуаціях, коли замість значення деякого типу за синтаксисом має бути об'єкт.

Розглянемо описаний вище клас string.

У рядках

string a="1234";

string b="4321";

відбувається, фактично, виклик відповідних конструкторів, а потім присвоєння екземплярам а та в відповідних абстрактних об'єктів. Аналогічні виклики відбуваються й у випадках, коли різнотипні дані зустрічаються в деяких арифметичних виразах. Наприклад:

class complex {

//...

complex(double f){re=f;im=0;}

};

Можна було б записати конструктор і так:

class complex {

//…

complex(double f,double i=0){re=f,im=i;}

};

Тоді в main()- функції можемо записати:

complex a(1,2),b(3);

a=b+121;

В останньому рядку відбувається неявний виклик конструктора complex(121), а потім виконується перевантажена операція додавання для екземплярів класу complex. Якщо конструктор наведеного вище типу не визначений, то можемо в даній ситуації зробити так:

a=operator+(b,complex(double(121),double(0)));

Використання конструкторів має деякі недоліки:

1. Виникають труднощі з неявним перетворенням типу від типу користувача до основного.

2. Не може бути неявного перетворення від нового типу до старого без зміни старого.

Позначимо через Т ім'я типу, X – деякий клас, тоді функція-член

X::operator Т();

здійснює перетворення типу з X на Т. Якщо ми використаємо описаний вище клас string та ініціалізуємо екземпляр класу

string myvalye="1234";,

то рядок long x=myvalue; буде помилковим, оскільки в класі не передбачено перетворення рядка на довге ціле.

Вихід з такої ситуації – перевантаження операції перетворення типу. У класі string необхідно описати функцію вигляду

operator long(){return atol(value);}

При роботі з різнотипними даними слід уникати можливих неоднозначностей. Розглянемо приклад:

class x{

public:

x(int){};

x(){};

};

class y {

public:

y(int){};

};

class z {

public:

z(x){};

z(y){};

};

Main()

{

z f(1);

}

При оголошенні екземпляра класу z f(1) у функції main() виникає неоднозначність. Згідно з оголошенням параметром конструктора класу z має виступати екземпляр або класу x, або y. Оскільки тут стоїть одиниця й у класах є конструктори, що дозволяють здійснити перетворення від цілого до типу відповідного класу, то таке перетворення має бути здійснене. Однак у якому класі це відбудеться, якщо вони обидва містять відповідні конструктори? Компілятор відстежує такі неоднозначності.

Для оптимізації роботи програми як формальні параметри перевантажених операцій краще використовувати посилання:

class matrix {

double m [300][400];

public:

matrix (){};

friend matrix operator+(matrix &,matrix &);};

Це дозволить уникнути копіювання даних, що займають значний обсяг пам'яті, у стек.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: