Студопедия

КАТЕГОРИИ:


Архитектура-(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)

Friend beta

Class beta

а потім оголосити клас alpha, а всередині визначення alpha оголосити дружність класу beta

Дружні функції.

Подібно дружнім класам, можливим є оголошення функцій - друзів - зовнішніх функцій або елементів-функцій іншого класу, що можуть здійснювати безпосередній доступ до всіх елементів та функцій класу, для якого вони дружні, в тому числі, оголошеними як protected та private. Правила опису та особливості дружніх функцій можна подати у такому порядку:

§ дружня функція оголошується в середині класу, до елементів якого потрібен доступ, з ключовим словом friend. Найчастіше у якості параметра такій функції повинен передаватися сам об'єкт, або посилання на об'єкт класу, оскільки вказівник this їй не передається.

§ дружня функція може бути звичайною функцією або методом іншого визначеного класу. На цю функцію не поширюються дії специфікаторів доступу, не має значення конкретне місце її розташування у протоколі.

§ одна функція може бути дружньою по відношенню до декількох класів

Для початку розглянемо випадок, коли дружня функція Externalдо класу А є зовнішньо

Class One {

private:

char* str;

public:

One () { Str="123";}

friend void Importante (One &a); //оголошення friend - функції

void External (One &a);

int main (void)

{

One r;

External(r);

return 0;

}

void External (One &a)

{

cout << a. str<<endl; // доступ до елемента-даних char*str з секції private

Таким чином, оголошення friend-функції Importante() у класі Oneвідкриває їй доступ до закритих та захищених членів даного класу.

Одна й та сама функція може бути оголошеною як friend двом класам одночасно.

Іноді це зручно, скажімо у випадках одночасної ініціалізації даних, хоча такі варіанти організації спричиняють неявний зв'язок між класами, їх подальшу залежність, що не є бажаним. Інша справа, коли класи пов'язані логікою програми:
 
Class Student; // неповне оголошення класу Class Teacher { friend void registration(); protected: int Nstudents; Student *plist[100]; // і т. д. }; Class Student { friend void registration(); protected: Teacher *Tch; int semesterhours; // і т. д. };

У вищенаведеному прикладі функція registration() може застосовуватися як класом Teacher, так і класом Student, не знаходячись у жодному з них, але пов'язуючи їх під час реєстрації (ініціалізації), що цілком нормально, виходячи з даного контексту.

Тепер щодо випадку, коли використовуються функції-друзі як елементи-функції. Зазвичай, дружньою у класі оголошується елемент-функція іншого класу. Ця функція матиме вільний доступ до захищеної та закритої частин класу, в якому вона оголошена як friend. На практиці це може виглядати таким чином:

Class А; // неповне оголошення класу Class В { private: char *s2; public: B() { s2= "В!!! "; } void show (A &c1); }; //--------------------------------------------------- Class A { friend void B::show(A&c1); private: char *s1; public: A() {s1="A!!! ";} }; //--------------------------------------------------- void main() { A c1; В c2; c2.show(c1); { void В::show(A&c1) } cout<< c1.s1<<s2<<endl; }

В реалізації видно, як функція show() звертається до закритої частини обох класів, хоча належить лише одному з них - класу В. Слід відмітити, що клас, в якому міститься прототип елемента-функції, повинен оголошуватися раніше класу, що вказує на функцію-елемент як дружню. Так для класу А, який оголошує дружньою для себе функцію B::show(A&c1), оголошення класу В попередньо повинно бути доступним компілятору.

2. ДРУЖНІ ФУНКЦІЇ ЯК МОСТИ МІЖ КЛАСАМИ.

Нехай нам необхідно, щоб функція працювала з об’єктами двох різних класів. Наприклад, функція буде розглядати об’єкти двох класів як аргументи і оброблятиме їх приховані дані. В програмі 22.8 приведено простий приклад FRIEND, що дає уявлення про роботу дружніх функцій в якості мостів між двома класами.

#include<iostream.h> #include<conio.h> #include<stdio.h> class beta; //------------------------------------- class alpha {private: int data; public: alpha():data(3) { } // конструктор без аргументів friend int frifunc(alpha,beta); }; //------------------------------------- class beta {private: int data; public: beta():data(5) { } //конструктор без аргументів friend int frifunc(alpha,beta); }; //------------------------------------- int frifunc(alpha a,beta b) { return a.data+b.data; } //------------------------------------- int main() {clrscr(); alpha aa; beta bb; cout<<frifunc(aa,bb)<<endl; return 0; }

Програма 22.8

В цій програмі ми бачимо два класи – alpha і beta. Конструктори цих класів задають їх єдині елементи даних у вигляді фіксованих значень 3 і 5. Нам необхідно, щоб функція frifunc() мала доступ до тих та інших прихованих даних, тому ми робимо її дружньою функцією. З цією метою всередині кожного класу використане ключове слово friend.

friend int frifunc(alpha,beta);

Це оголошення може бути розміщене де завгодно всередині класу. Немає жодної різниці, запишемо ми його в public - чи private -секцію.

Об’єкт кожного класу передається як параметр функції frifunc(), і функція має доступ до прихованих даних обох класів через ці аргументи. Функція додає значення даних і повертає їх суму.

Нагадаємо, що до класу не можна звертатися до того, як він оголошений в програмі. Оголошення функції frifunc() в класі alpha посилається на клас beta, а, отже, beta повинен бути оголошений до alpha. Звідси означення class beta; на початку програми.

Треба відмітити, що ідея дружніх функцій дещо сумнівна. Під час розробки С++ на цю тему велися суперечки і приводилися аргументи проти включення в мову такої можливості. З одного боку, дружні функції підвищують гнучкість мови, з іншого - вони не відповідають принципу обмеження доступу до даних, згідно з яким тільки функції-члени можуть мати доступ до прихованих даних класу.

Наскільки серйозно суперечить єдності концепції використання дружніх функцій? Дружня функція оголошується такою в тому класі, до даних якого вона пізніше й матиме доступ. Таким чином, програміст, що не має доступу до вихідного коду класу, не може зробити функцію дружньою. В цьому сенсі цілісність даних зберігається. Але все одно такі функції можуть призвести до «spaghetti code» (код з надто великою кількістю передач управління), коли численні дружні функції фактично стирають границі між класами. З цієї причини дружні функції повинні бути принаймні розкидані по програмі і зустрічатися як можна рідше.

Приклад використання дружніх функцій.

Все-таки інколи дружні функції занадто зручні, щоб від них відмовлятися. Найзагальнішим прикладом цього є ситуація, коли вони використовуються для підвищення багатосторонності перезавантажуваних операцій. Програма 22.9 показує обмеженість використання таких операторів без використання дружніх функцій. Програма працює з раніше вже нами використовуваним типом Distance (англійські міри довжини).

#include<iostream.h> #include<conio.h> #include<stdio.h> #include<bios.h> class Distance {int feet; float inches; public: Distance():feet(0),inches(0.0) {} Distance(float fltfeet) {feet=(int)fltfeet; inches=12*(fltfeet-feet); } Distance(int ft,float in) {feet=ft;inches=in;} void showdist() {cout<<feet<<"\'-"<<inches<<'\'';} Distance operator+(Distance); }; //---------------------------------------- Distance Distance::operator+(Distance d2) {int f=feet+d2.feet; float i=inches+d2.inches; if(i>=12.0) {i-=12.0;f++;} return Distance(f,i); } //---------------------------------------- int main() {clrscr(); Distance d1=2.5; Distance d2=1.25; Distance d3; cout<<"\nd1=";d1.showdist(); cout<<"\nd2=";d2.showdist(); d3=d1+10.0; cout<<"\nd3=";d3.showdist(); // d3=10.0+d1; // cout<<"\nd3=";d3.showdist(); cout<<endl; bioskey(0); return 0; }

Програма 22.9

В цій програмі оператор «+» перевстановлений на додавання двох об’єктів типу Distance. Крім того, наявний конструктор з одним аргументом, який переводить значення типу float в значення типу Distance.

Якщо є такий конструктор, то можна записати вираз: d3=10.0+d1;

Перезавантаженому + потрібні об’єкти типу Distance справа і зліва, але, знайшовши справа аргумент типу float, у відповідності з конструктором він переводить цей float в Distance і здійснює додавання.

Але що трапиться, коли ми переставимо доданки місцями? d3=10.0+d1;

Цей вираз не буде оброблений як належить, оскільки об’єкт, чиїм методом є перезавантажений +, повинен бути змінною, що знаходиться зліва від оператора. Коли ми поміщаємо туди операнд іншого типу чи константу, компілятор використає + для додавання з цим типом (в даному випадку float) замість того, щоб додавати об’єкти типу Distance. Але цей оператор не вміє конвертувати float в Distance, тому не може виконати додавання. Вийти з цієї ситуації можна, створивши новий об’єкт типу Distance.

d3=Distance(10.)+d1;

Такий вираз є цілком коректним, але неелегантним і неочевидним. Як написати звичний для нас вираз, що містив би потрібні типи справа і зліва від оператора? За допомогою дружньої функції.

Програма 22.10 демонструє, як саме це зробити.

#include<iostream.h> #include<conio.h> #include<stdio.h> class Distance { int feet; float inches; public: Distance():feet(0),inches(0.0) {} Distance(float fltfeet) {feet=(int)fltfeet; inches=12*(fltfeet-feet); } Distance(int ft,float in) {feet=ft;inches=in;} void showdist() {cout<<feet<<”\’-“<<inches<<’\’’;} friend Distance operator+(Distance,Distance); }; //---------------------------------------- Distance operator+(Distance d1,Distance d2) {int f=d1.feet+d2.feet; float i=d1.inches+d2.inches; if(i>=12.0) {i-=12.0;f++;} return Distance(f,i); } //---------------------------------------- int main() { clrscr(); Distance d1=2.5; Distance d2=1.25; Distance d3; cout<<”\nd1=”;d1.showdist(); cout<<”\nd2=”;d2.showdist(); d3=d1+10.0; cout<<”\nd3=”;d3.showdist(); d3=10.0+d1; cout<<”\nd3=”;d3.showdist(); cout<<endl; return 0; }

Програма 22.10

Перезавантажена операція + зроблена дружньою:

friend Distance operator+(Distance,Distance);

};

//----------------------------------------

Distance operator+(Distance d1,Distance d2)

Зверніть увагу, що у попередньому прикладі (програма 22.9) – перезавантажуваний + є методом, а в програмі 22.10 – дружньою функцією. Будучи звичайним методом, + оперував одним з доданків як об’єктом, членом якого він був, а другим – як операндом. Ставши дружньою функцією, + став розглядати обидва об’єкти в якості аргументів. З цієї причини змінні feet та inches з попередньої програми були замінені змінними d1.feet та d1.inches, оскільки цей об’єкт став аргументом.

Запам’ятаймо: щоб зробити функцію дружньою, її оголошення всередині класу слід починати з ключового слова friend. Визначення і виклик функції не змінюються.

3. ДРУЖНІСТЬ І ФУНКЦІОНАЛЬНИЙ ЗАПИС.

Інколи дружня функція дозволяє використовувати зрозуміліший синтаксис виклику функції, ніж звичайний метод.

Н а п р и к л а д, нехай нам потрібна функція, що підносить до квадрату екземпляр об’єкту типу Distance, що повертає значення в квадратних футах як тип float.

Програма 22.11 показує, як це можна зробити за допомогою звичайного методу.

#include<iostream.h>

#include<conio.h>

#include<stdio.h>

#include<bios.h>

//-------------------------------------------------

class Distance

{int feet;

float inches;

public:

Distance():feet(0),inches(0.0)

{}

Distance(float fltfeet)

{feet=(int)fltfeet;

inches=12*(fltfeet-feet);

}

Distance(int ft,float in)

{ feet=ft;inches=in;}

void showdist()

{cout<<feet<<”\’-“<<inches<<’\’’;}

float square();

};

//-------------------------------------------------

float Distance::square()

{float fltfeet=feet+inches/12;

float feetsqrd=fltfeet*fltfeet;

return feetsqrd;

}

//-------------------------------------------------

int main()

{

clrscr();

Distance dist(3,6.0);

float sqft;

sqft=dist.square();

cout<<”\n Distance=”;dist.showdist();

cout<<”\n Distance^2=”<<sqft<<” кв футів\n”;

bioskey(0);

return 0;

}

Програма 22.11

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

sqft=dist.square();

Цей запис є цілком коректний, але значно зрозумілішим був би функціональний запис:

sqft=square(dist);

Такого ефекту можна досягти, зробивши square() дружньою функцією для класу Distance. Це показано в програмі 22.12

#include<iostream.h>

#include<conio.h>

#include<stdio.h>

#include<bios.h>

//--------------------------------------

class Distance

{int feet;

float inches;

public:

Distance():feet(0),inches(0.0)

{}

Distance(float fltfeet)

{feet=(int)fltfeet;

inches=12*(fltfeet-feet);

}

Distance(int ft,float in)

{feet=ft;inches=in;}

void showdist()

{cout<<feet<<”\’-“<<inches<<’\’’;}

friend float square(Distance);

};

//--------------------------------------

float square(Distance d)

{float fltfeet=d.feet+d.inches/12;

float feetsqrd=fltfeet*fltfeet;

return feetsqrd;

}

//--------------------------------------

int main()

{clrscr();

Distance dist(3,6.0);

float sqft;

sqft=square(dist);

cout<<”\nDistance=”;dist.showdist();

cout<<”\nDistance^2=”<<sqft<<” кв футів\n”;

bioskey(0);

return 0;

}

Програма 22.12

Функція square() в попередній програмі не потребувала аргументів, будучи звичайним методом, натомість в програмі 22.12 їй вже потрібні аргументи. Загалом кажучи, дружня функція потребує на один аргумент більше, ніж метод.

<== предыдущая лекция | следующая лекция ==>
 | Сучасний стан розвитку конфігурованих комп’ютерів
Поделиться с друзьями:


Дата добавления: 2014-01-07; Просмотров: 304; Нарушение авторских прав?; Мы поможем в написании вашей работы!


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



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




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