Множинне перезавантаження
Ми розглянули різні приклади використання операції + для додавання інтервалів та об’єднання рядків. Можна використовувати обидва написані нами класи в одній програмі, при цьому компілятор знатиме, яка з функцій нам потрібна, оскільки він вибирає функцію, виходячи з операндів операції. Нагадаємо, що таке явище є проявом принципу поліморфізму.
Операції порівняння
Розглянемо перезавантаження операцій іншого типу, а саме операцій порівняння.
Порівняння об’єктів класу Distance
Перезавантажимо операцію «менше ніж» (<) в класі Distance для того, щоб мати можливість порівнювати об’єкти цього класу. Приведемо лістінг програми 14.7
#include <iostream.h>
#include <conio.h>
#include <bios.h>
class Distance
{private:
int feet;
float inches;
public:
Distance():feet(0),inches(0.0) //Конструктор без аргументів
{ }
//Конструктор з двома аргументами
Distance(int ft,float in):feet(ft),inches(in)
{ }
void getdist()
{cout <<”\nВведіть число футів “; cin >>feet;
cout << “Дюймів “; cin>>inches;
}
void showdist()
{cout <<feet << “\’ “<< inches <<”\’’”;}
Distance operator+(Distance) const;
int operator<(Distance) const;
};
//dodavanna d2 I d3
Distance Distance::operator+(Distance d2) const
{
int f=feet+d2.feet;
float i=inches+d2.inches;
if(i>=12.0)
{i-=12.0;
f++;}
return Distance(f,i);
}
int Distance::operator<(Distance d2) const
{float bf1=feet+inches/12;
float bf2=d2.feet+d2.inches/12;
return (bf1<bf2)?1:0;
}
int main()
{
clrscr();
Distance dist1,dist3,dist4;
dist1.getdist();
Distance dist2(11,6.25);
dist3=dist1+dist2;
dist4=dist1+dist2+dist3;
cout <<”\ndist1=”;dist1.showdist();
cout << “\ndist2=”;dist2.showdist();
cout << “\ndist3=”;dist3.showdist();
cout << “\ndist4=”;dist4.showdist();
cout <<endl;
if (dist1<dist2)
cout<<”\ndist1<dist2”;
else
cout<<”\ndist1>=dist2”;
cout <<endl;
bioskey(0);
return 0;
}
Програма 14.7
Програма порівнює інтервал, заданий користувачем, з інтервалом, визначеним у програмі. Залежно від одержаного результату, на екран виводиться одне з двох речень. Оскільки у використовуваному нами компіляторі відсутній булівський тип даних, а істинним вважається всякий числовий вираз, відмінний від 0, ми у випадку , коли порівння виконується, повертаємо 1, а іншому випадку – 0.
Порівняння рядків
Розглянемо інший приклад перезавантаження оператора. Тепер це буде оператор == (дорівнює), ми використовуватимемо його для об’єктів класу String, повертаючи 1, коли вони одинакові, і 0 – коли різні. Далі приведений лістінг програми 14.8, яка і здійснює перезавантаження.
#include <iostream.h>
#include <conio.h>
#include <bios.h>
#include <string.h>
#include <stdlib.h>
class String //clas dla ryadkiv
{private:
enum {SZ=80}; // max dla ryadkiv
char str[SZ]; //masyv dla ryadka
public:
String ()
{strcpy(str,””);}
String(char s[])
{strcpy(str,s);}
void display() const
{cout <<str;}
void getstr()
{cin.get(str,SZ);}
//operator
String operator+(String ss) const
{String temp;
if (strlen(str)+strlen(ss.str)<SZ)
{strcpy(temp.str,str);
strcat(temp.str,ss.str);
}
else
{cout <<”\nПереповнення!”;
exit(1);}
return temp;
}
int operator==(String ss) const
{return (strcmp(str,ss.str)==0)?1:0;}
};
//////////////////
int main()
{clrscr();
String s1=”yes”;
String s2=”no”;
String s3;
cout <<”Введіть ‘yes’ or ‘no’:”;
s3.getstr();
if (s3==s1)
cout<<”Введено yes\n”;
else
if (s3==s2)
cout<<”Введено no\n”;
else
cout<<”Помилка вводу\n”;
bioskey(0);
return 0;
}
Програма 14.8
Функція operator==() використовує бібліотечну функцію strcmp() для порівняння двох рядків. Ця функція повертає 0, якщо рядки рівні, від’ємне число, коли перший рядок менший (в лексикографічному сенсі) за другий, і додатнє число в протилежному випадку.
Інші операції порівняння теж можуть бути перевизна для порівняння рядків.
Операції арифметичного присвоювання
Закінчимо вивчення перезавантаження бінарних операцій на прикладі арифметичного присвоювання +=. Ця операція виконує присвоювання і додавання одночасно. Ми будемо використовувати цю операцію для додавання інтервалів, записуючи результат у змінну, що означає перший інтервал. Приведемо лістінг програми 14.9 (базується на програмі 14.7)
#include <iostream.h>
#include <conio.h>
#include <bios.h>
class Distance
{private:
int feet;
float inches;
public:
Distance():feet(0),inches(0.0) //Конструктор без аргументів
{ }
//Конструктор з 2 аргументами
Distance(int ft,float in):feet(ft),inches(in)
{ }
void getdist()
{cout <<”\nВведіть число футів “; cin >>feet;
cout << “Дюймів “; cin>>inches;
}
void showdist()
{cout <<feet << “\’ “<< inches <<”\’’”;}
Distance operator+(Distance) const;
int operator<(Distance) const;
void operator+= (Distance);
};
//Додавання d2 I d3
Distance Distance::operator+(Distance d2) const
{
int f=feet+d2.feet;
float i=inches+d2.inches;
if(i>=12.0)
{i-=12.0;
f++;}
return Distance(f,i);
}
int Distance::operator<(Distance d2) const
{float bf1=feet+inches/12;
float bf2=d2.feet+d2.inches/12;
return (bf1<bf2)?1:0;
}
void Distance::operator+=(Distance d2)
{feet+=d2.feet;
inches+=d2.inches;
if (inches>=12.0)
{inches-=12.0;
feet++;
}
}
int main()
{
clrscr();
Distance dist1;
dist1.getdist();
cout<<”\ndist1=”;dist1.showdist();
Distance dist2(11,6.25);
cout<<”\ndist2=”;dist2.showdist();
dist1+=dist2;
cout<<”\nПісля операції:”;
cout<<”\ndist1=”;dist1.showdist();
cout<<endl;
bioskey(0);
return 0;
}
Програма 14.9
Зауважимо, що у функції operator+=() цієї програми об’єктом, що приймає значення суми, є об’єкт, який викликає цю функцію. Тому feet та inches є заданими величинами, а не тимчасовими змінними, які використовуються тільки для повернутого об’єкту. Функція operator+=() не повертає жодного значення і має тип void. Але, якщо ми захочемо використати цю операцію в складніших виразах, таких як
dist=dist1+=dist2;
то нам буде потрібне значення, яке повертається. Ми можемо ввести його, записавши в кінці визначення функції operator+=() рядок
return Distance(feet, inches);
в якій безіменний об’єкт ініціалізується тим самим значенням, що й об’єкт, який викликає функцію, і потім повертається.
Операція індексації масиву
Операція індексації, яка звичайно використовується для доступу до елементів масиву, може бути перезавантажена. Це корисно в тому випадку, коли ми хочемо змінити спосіб роботи С++ з масивами. Наприклад, нам може знадобитися «безпечний масив», в якому закладена автоматична перевірка використовуваного для доступу до масиву індексу елемента. Вона буде перевіряти, чи не вийшли ми за межі масиву.
Реалізувати перезавантаження операції можна різними способами. Далі представлені три:
§ з використанням двох окремих методів put() і get() (програма 14.10)
§ з використанням методу access(), що використовує повернення за посиланням (програма 14.11)
§ перезавантажена операція [], що використовує повернення за посиланням (програма 14.12).
#include <iostream.h>
#include <conio.h>
#include <bios.h>
#include <process.h>
const int LIMIT=100;
class safearray
{private:
int arr[LIMIT];
public:
void putel(int n,int elvalue)
{if (n<0 || n>=LIMIT)
{cout<<”\nПомилковий індекс!”;exit(1);}
arr[n]=elvalue;
}
int getel(int n) const
{if(n<0|| n>=LIMIT)
{cout<<”\nПомилковий індекс!”;exit(1);}
return arr[n];
}
};
////////////////
int main()
{
clrscr();
safearray sal;
//elementy
for (int j=0;j<LIMIT;j++)
sal.putel(j,j*10);
//показати
for (j=0;j<LIMIT;j++)
{int temp=sal.getel(j);
cout<<”Елемент “<<j<<”=”<<temp<<endl;
}
bioskey(0);
return 0;
}
Програма 14.10
#include <iostream.h>
#include <conio.h>
#include <bios.h>
#include <process.h>
const int LIMIT=10;
class safearray
{private:
int arr[LIMIT];
public:
int& access(int n)
{
if (n<0||n>=LIMIT)
{cout<<"\nПомилковий індекс:";exit(1);}
return arr[n];
}
};
////////////////
int main()
{
clrscr();
safearray sal;
//елементи
for (int j=0;j<LIMIT;j++)
sal.access(j)=j*10;
//показати
for (j=0;j<LIMIT;j++)
{int temp=sal.access(j);
cout<<"Елемент "<<j<<"="<<temp<<endl;
}
bioskey(0);
return 0;
}
Програма 14.11
У цій програмі рядок
sal.access(j)=j*10;
означає, що значення j*10 буде поміщене в елемент масиву arr[j], посилання на який повертається методом.
#include <iostream.h>
#include <conio.h>
#include <bios.h>
#include <process.h>
const int LIMIT=10;
class safearray
{private:
int arr[LIMIT];
public:
int& operator[](int n)
{
if (n<0||n>=LIMIT)
{cout<<"\nПомилковий індекс:";exit(1);}
return arr[n];
}
};
////////////////
int main()
{
clrscr();
safearray sal;
//elementy
for (int j=0;j<LIMIT;j++)
sal[j]=j*10;
//show
for (j=0;j<LIMIT;j++)
{int temp=sal[j];
cout<<"Елемент "<<j<<"="<<temp<<endl;
}
bioskey(0);
return 0;
}
Програма 14.12
В цій програмі ми можемо використовувати звичайний запис операції індексації масиву
sal[j]=j*10;
і
temp=sal[j]
для вводу-виводу елементів масиву.
Перетворення типів
Ми вже знаємо, що операція присвоєння = використовується для присвоєння значення змінної певного типу змінній того ж типу, причому це може бути як основний тип, так і тип, визначений користувачем. Але що трапиться, коли з різних сторін знаку = записані змінні різних типів? Насправді це досить складне питання, яким і займемося. Спершу розглянемо, як компілятор виконує перетворення основних типів, яке відбувається автоматично. Потім пояснимо кілька ситуацій, де компілятор не виконує автоматичного перетворення і ми самі повинні визначити його дії. В ці ситуації включені перетворення між основними і визначеними користувачем типами та перетворення між різними типами, визначеними користувачем.
У таких мовах, як Паскаль, здійснені спроби вивільнити розробника від необхідності проробляти подібні перетворення. Однак філософія С++ - це гнучкість, надана можливістю здійснювати всеможливі перетворення.
Перетворення основних типів у основні типи
Коли ми пишемо рядок типу
intvar=floatvar;
де intvar – змінна цілого типу, а floatvar – змінна дійсного типу, то передбачаємо, що компілятор викличе спеціальну функцію для перетворення значення змінної floatvar, яка має формат числа з плаваючою крапкою, в формат цілого числа. Звичайно, існує багато таких перетворень: з float в double, з char у float та інші. Кожне таке перетворення має свою процедуру, вбудовану у компілятор, яка відкривається в залежності від типів змінних, які проставлені з обох сторін знаку =. Ми кажемо, що ці перетворення неявні, оскільки вони не відображаються у лістінгу.
Інколи ми хочемо змусити компілятор перетворити один тип у інший. Далі представлена невеличка програма, де тип float примусово перетворюється в int.
#include <iostream.h>
#include<bios.h>
#include<conio.h>
int main()
{clrscr();
float a=1.62;
int b;
b=(int)a;
cout<<"a="<<a<<" b="<<b;
bioskey(0);
return 0;
}
Перетворення здійснює оператор b=(int)a; у деяких версіях С++ з цією метою передбачений спеціальний оператор static_cast. У цьому випадку ми здійснюємо явне перетворення, але воно використовує ті ж вбудовані процедури, що й неявне.
Перетворення об’єктів у основні типи і навпаки
Якщо нам потрібно здійснити перетворення визначених користувачем типів у основні типи, ми не можемо покластися на вбудовані функції, оскільки компілятору не відомо про визначені користувачем типи нічого, крім того, що ми самі йому повідомимо. Тому ми повинні самостійно написати функції для перетворення типів.
В наступному прикладі показано, як відбувається перетворення основного типу в тип, визначений користувачем. В цьому прикладі в якості визначеного користувачем типу ми будемо використовувати клас Distance з попередніх прикладів, а в якості основного типу – тип float, який ми використовували для змінної, що містить метри.
В прикладі (програма 14.13) приведені обидва варіанти: з Distance у float і навпаки.
#include <iostream.h>
#include <conio.h>
#include <bios.h>
#include<math.h>
class Distance
{private:
const float MTF; //коефіцієнт переведення
int feet;
float inches;
public:
Distance():feet(0),inches(0.0),MTF(3.280833F)
{}
Distance(float meters):MTF(3.280833F) //конструктор переведення дійсного
//числа в об’єкт
{float flcfeet=MTF*meters;
feet=int(flcfeet);
inches=12*(flcfeet-feet);
}
Distance (int ft,float in):feet(ft),inches(in),MTF(3.280833F)
{}
void getdist()
{cout<<"\nВведіть фути ";cin>>feet;
cout<<"\nдюйми ";cin>>inches;
}
void showdist() const
{cout <<feet << "\' "<< inches <<"\''";}
operator float()const //оператор переведення об’єкту в дійсне число
{float fracfeet=inches/12;
fracfeet+=float(feet);
return fracfeet/MTF;
}
};
////////////
int main()
{clrscr();
float mtrs;
Distance dist1=2.35F;//конструктор, що переводить метри в фути і дюйми
cout <<”\ndist1=”;dist1.showdist();
mtrs=(float)dist1; //оператор перетворення в метри
cout<<”\ndist1=”<<mtrs<<” meters\n”;
Distance dist2(5,10.25);
cout <<”\ndist2=”;dist2.showdist();
mtrs=dist2; //неявне перетворення типу
cout<<”\ndist2=”<<mtrs<<”meters\n”;
//dist2=mtrs; //помилковий вираз
bioskey(0);
return 0;
}
Програма 14.13
Для переходу від основного тпу – в нашому випадку float – до визначеного користувачем типу Distance ми використовуємо конструктор з одним аргументом. Його інколи називають конструктором перетворення. От як він виглядає в програмі 14.13
Distance(float meters):MTF(3.280833F) //конструктор переведення дійсного
//числа в об’єкт
{float flcfeet=MTF*meters;
feet=int(flcfeet);
inches=12*(flcfeet-feet);
}
Цей конструктор викликається, коли створюється об’єкт класу Distance з одним аргументом. Конструктор передбачає, що аргумент являє собою метри. Він перетворює аргумент в фути і дюйми і присвоює одержане значення об’єкту. Таким чином, перетворення з метрів у змінну типу Distance виконується разом зі створенням об’єкту в рядку:
Distance dist1=2.35F;
Для перетворення типу користувача в основний тип ми створили спеціальний оператор:
operator float()const //оператор переведення об’єкту в дійсне число
{float fracfeet=inches/12;
fracfeet+=float(feet);
return fracfeet/MTF;
}
Ця операція приймає значення об’єкту класу Distance, перетворює його значення у тип float і повертає це значення.
Операція може бути викликана явно:
mtrs=(float)dist1;
або за допомогою звичайного присвоювання
mtrs=dist2;
В обох випадках відбувається перетворення об’єкту типу Distance в еквівалентне значення типу float.
Перетворення рядків в об’єкти класу String і навпаки
Розглянемо інший приклад, в якому використані конструктор з одним аргументом і оператор перетворення. тут використовується клас String, з яким вже раніше працювали у програмі 14.8.
Далі приведено лістінг програми 14.14.
#include <iostream.h>
#include <conio.h>
#include <bios.h>
#include <string.h>
#include <stdlib.h>
class String //Клас для рядків
{private:
enum {SZ=80}; // max для рядків
char str[SZ]; //масив для рядків
public:
String () //конструктор без параметра
{str[0]=’\x0’;}
String(char s[])
{strcpy(str,s);}
void display() const
{cout <<str;}
void getstr()
{cin.get(str,SZ);}
//operator
operator char*( );
};
String::operator char*()
{return str;}
//////////////////
int main()
{clrscr();
String s1;
char xstr[]=”Звичайний рядок “;
s1=xstr; //неявний конструктор з 1 параметром
s1.display();
String s2=”Інший рядок”; //конструктор з параметром;
cout<<endl<<(char*)s2;
cout<<endl;
bioskey(0);
return 0;
}
Програма 14.14
Конструктор з одним аргументом перетворює звичайний рядок (масив елементів типу char) в об’єкт класу String:
String(char s[])
{strcpy(str,s);}
Рядок передається в якості аргументу і коміюється у змінну str новоствореного об’єкту класу String, використовуючи бібліотечну функцію strcpy(). Це перетворення буде використовуватися, коли створюється об’єкт класу String:
String s2=”Інший рядок”;
або буде використовуватися у виразі присвоювання
s1=xstr;
де s1 - об’єкт класу String, а змінна xstr – просто рядок.
Операція перетворення використовується для перетворення об’єкту класу String у рядок:
String::operator char*()
{return str;}
Зірочка в цьому виразі означає вказівник на. Це інший спосіб оголошення змінної рядкового типу.
Оператор перетворення використовується компілятором у рядку
cout<<endl<<(char*)s2;
Тут s2 – змінна, що використовується як аргумент для перезавантаженої операції <<. Оскільки операції << нічого не відомо про визначений користувачем тип String, то компілятор намагатиметься перетворити змінну s2 на один з відомих йому типів. Ми визначимо тип, до якого хочемо перетворити змінну, за допомогою оператора (char*)s2 Оператор шукає перетворення від типу String до рядкового типу, і, знайшовши нашу функцію char*(), виконує її для генерації рядка, який потім буде виведений через операцію <<. Метод display стає зайвим і може бути видаленим.
Програма 14.14 демонструє, що перетворення типів відбувається автоматично не лише у виразах присвоювання, але і в інших підходящих місцях, таких як пересилання аргументів операціям (наприклад, <<) чи функціям. При передачі в операцію чи функцію аргументу неправильного типу, вони перетворюють його до прийнятного типу, якщо ми визначили таке перетворення.
Зауважимо, що ми не можемо використовувати явний вираз присвоювання для перетворення об’єкту класу String до змінної рядкового типу.
xstr=s2;
оскільки xstr є масивом. Щоб щось йому присвоїти, нам потрібно перезавантажити операцію присвоєння.
Перетворення об’єктів класів в об’єктів інших класів
Для перетворення між об’єктами різних визначених користувачем класів використовуються ті ж два методи перетворень, що й для перетворень між основними типами і об’єктами користувача. Тобто ми можемо використати конструктор з одним аргументом або операцію перетворення. Вибір залежить від того, чи хочемо ми записати функцію перетворення в класі для вихідного об’єкту чи для об’єкту призначення.
В подальших прикладах ми будемо працювати з двома класами, які відповідають різним способам вимірювання часу: 12-годинним і 24-годинним. Клас time12 буде використовувати години і хвилини, а також відмітки «до обіду» і «після обіду». Клас time24 відображатиме години, хвилини і секунди.
Функція у вихідному об’єкті
В програмі 14.15 ми розглянемо випадок, коли функція перетворення розміщена у вихідному класі. В цьому випадку вона буде реалізована у вигляді операції перетворення.
#include <iostream.h>
#include <conio.h>
#include <bios.h>
#include <string.h>
class time12
{private:
int pm;
int hrs;
int mins;
public:
time12():pm(1),hrs(0),mins(0)
{ }
time12(int ap,int h,int m):pm(ap),hrs(h),mins(m)
{ }
void display() const
{cout<<hrs<<":";
if (mins<10)
cout<<'0';
cout<<mins<<"-";
if(pm)
cout<<"p.m";
else
cout<<"a.m";
}
};
class time24
{private:
int hours;
int minutes;
int seconds;
public:
time24(): hours(0),minutes(0),seconds(0)
{}
time24(int h,int m,int s):hours(h),minutes(m),seconds(s)
{}
void display()const
{if(hours<10) cout<<"0";
cout<<hours<<":";
if(minutes<10) cout<<"0";
cout<<minutes<<":";
if (seconds<10) cout<<"0";
cout <<seconds;
}
operator time12()const;
};
time24::operator time12() const
{int hrs24=hours;
int pm=hours<12?0:1;
int roundmins=seconds<30?minutes:minutes+1;
if (roundmins==60)
{roundmins=0;
++hrs24;
if (hrs24==12||hrs24==24)
pm=(pm==1)?0:1;
}
int hrs12=(hrs24<13)?hrs24:hrs24-12;
if (hrs12==0)
{hrs12=12;
pm=1;
}
return time12(pm,hrs12,roundmins);
};
////////
int main()
{clrscr();
int h,m,s;
while(1)
//набрати 24 для виходу
{cout <<"Введіть час у 24-форматі:\n";
cout <<"Години (0-23):";cin>>h;
if (h>23)
return(1);
cout <<"Хвилини";cin>>m;
cout<<"Секунди:";cin>>s;
time24 t24(h,m,s);
cout<<"Вихідний час";
t24.display();
time12 t12=t24;
cout <<"\nV 12-год формат: ";
t12.display();
cout<<"\n\n";
};
return 0;
}
Програма 14.15
У функції main() ми визначили об’єкт класу time24, названий t24, і присвоїли йому значення годин, хвилин і секунд, одержані від користувача. Ми також визначили об’єкт класу time12, названий t12, та ініціалізували його значенням об’єкту t24 в рядку
time12 t12=t24;
Оскільки це об’єкти різних класів, то для здійснення присвоювання необхідне перетворювання. Ми визначили операцію перетворення в класі time24. Її оголошення
time24::operator time12() const
Ця функція перетворює об’єкт, що її викликає, в об’єкт класу time12 і повертає функції main() об’єкт, що потім буде присвоєний змінній t12.
Функція в об’єкті призначення
Розглянемо, як виконується це перетворення, коли функція перетворення знаходиться в класі призначення. В цій ситуації використовується конструктор з одним аргументом. Однак все ускладнюється тим фактом, що конструктор класу призначення повинен мати доступ до даних вихідного класу для виконання перетворення. Поля класу time24 позначені як private, тому ми повинні написати спеціальні методи в класі time24, які дозволять прямий доступ до нього. Це методи getHrs(), getMins() та getSecs().
Лістінг програми 14.16.
#include <iostream.h>
#include <conio.h>
#include <bios.h>
#include <string.h>
class time24
{
private:
int hours;
int minutes;
int seconds;
public:
time24(): hours(0),minutes(0),seconds(0)
{}
time24(int h,int m,int s):hours(h),minutes(m),seconds(s)
{}
void display()const
{if(hours<10) cout<<”0”;
cout<<hours<<”:”;
if(minutes<10) cout<<”0”;
cout<<minutes<<”:”;
if (seconds<10) cout<<”0”;
cout <<seconds;
}
int getHrs() const
{return hours;}
int getMins() const
{return minutes;}
int getSecs() const
{return seconds;}
} ;
////////////////////////
class time12
{private:
int pm;
int hrs;
int mins;
public:
time12():pm(1),hrs(0),mins(0)
{ }
time12(time24);
time12(int ap,int h,int m):pm(ap),hrs(h),mins(m)
{ }
void display() const
{cout<<hrs<<”:”;
if (mins<10)
cout<<"0";
cout<<mins<<"-";
if(pm)
cout<<”p.m”;
else
cout<<»a.m»;
}
};
time12::time12(time24 t24)
{int hrs24=t24.getHrs();
pm=t24.getHrs()<12?0:1;
mins=(t24.getSecs()<30)?t24.getMins():t24.getMins()+1;
if (mins==60)
{mins=0;
++hrs24;
if(hrs24==12||hrs24==24)
pm=(pm==1)?0:1;
}
hrs=(hrs<13)?hrs24:hrs24-12;
if (hrs==0)
{hrs=12;pm=0;}
};
////////
int main()
{clrscr();
int h,m,s;
while(1)
//Введіть 24 для виходу
{cout <<”Введіть час у 24 форматі:\n”;
cout <<”Години (0-23):”;cin>>h;
if (h>23)
return(1);
cout <<”Хвилини:”;cin>>m;
cout<<”Секунди:”;cin>>s;
time24 t24(h,m,s);
cout<<”Вихідний час”;
t24.display();
time12 t12=t24;
cout <<”\nУ 12-год формат: “;
t12.display();
cout<<”\n\n”;
};
return 0;
}
Програма 14.16
Тут функцією перетворення є конструктор з одним аргументом з класу time12.
time12(time24);
Вона встановлює для об’єкту, що її викликав, значення, яке відповідає значенню об’єкту класу time24, одержаному в якості аргументу.
Функція main() в цій програмі така ж, як і в попередній. В цьому рядку знову відбувається перетворення типів від time24 до time12, але вже з використанням конструктора з одним аргументом
time12 t12=t24;
Деякі рекомендації щодо перезавантаження операцій і перетворення типів
Коли які перетворення використовувати?
Як ми вже встановили, якщо перетворення типів передбачене в класі призначення, то слід використовувати конструктор з одним аргументом, а якщо у вихідному класі – то використовується операція перетворення. Який саме спосіб слід вибирати в конкретних випадках? Якщо обидва класи повністю доступні, то можна вибрати будь-який. Але так буває не завжди. Якщо ми купуємо чужу бібліотеку класів, то можемо не мати доступу до її вихідних файлів. Якщо ми будемо використовувати об’єкт такого класу в якості вихідного у перетворенні, то можемо дістати доступ лише до класу призначення, тому використовуватимемо конструктор з одним аргументом. Якщо ж об’єкт призначення належить бібліотечному класу, то ми повинні виконувати операцію перетворення у вихідному класі.
«Підводні камені» перезавантаження операцій і перетворення типів
Перезавантаження операцій і перетворення типів дає нам змогу створити, по суті, нову мову. Нехай a, b, c - об’єкти визначеного користувачем класу, а операція + перезавантажена, при цьому рядок
a=b+c;
може означати що-небудь відмінне від того, що було б, якби a,b, c належали до якогось із основних типів. Можливість перевизначення вбудованих блоків мови добра тим, що ми моджемо зробити лістінг програми більш зрозумілим і читабельним. Але можливий і інший результат, коли наш лістінг стане, навпаки, менш зрозумілим і складнішим. Приведемо кілька рекомендацій з цього приводу.
Дата добавления: 2015-08-26; просмотров: 648;