Бьерн Страуструп. Язык программирования С++ Второе дополненное издание



Pdf көрінісі
бет106/256
Дата11.07.2022
өлшемі2,87 Mb.
#37591
1   ...   102   103   104   105   106   107   108   109   ...   256
5.4 Еще о классах 
В этом разделе описаны дополнительные свойства класса. Описан способ обеспечить доступ к частным 
членам в функциях, не являющихся членами ($$5.4.1). Описано, как разрешить коллизии имен членов 
($$5.4.2) и как сделать описания классов вложенными ($$5.4.3), но при этом избежать нежелательной 
вложенности ($$5.4.4). Вводится понятие статических членов (static), которые используются для 
представления операций и данных, относящихся к самому классу, а не к отдельным его объектам 
($$5.4.5). Раздел завершается примером, показывающим, как можно построить дискриминирующее 
(надежное) объединение ($$5.4.6). 
5.4.1 Друзья 
Пусть определены два класса: vector (вектор) и matrix (матрица). Каждый из них скрывает свое 
представление, но дает полный набор операций для работы с объектами его типа. Допустим, надо 
определить функцию, умножающую матрицу на вектор. Для простоты предположим, что вектор имеет 
четыре элемента с индексами от 0 до 3, а в матрице четыре вектора тоже с индексами от 0 до 3. Доступ 
к элементам вектора обеспечивается функцией elem(), и аналогичная функция есть для матрицы. 
Можно определить глобальную функцию multiply (умножить) следующим образом: 
vector multiply(const matrix& m, const vector& v); 

vector 
r; 
for (int i = 0; i<3; i++) { // r[i] = m[i] * v; 
r.elem(i) 

0; 
for (int j = 0; j<3; j++) 
r.elem(i) 
+=m.elem(i,j) 

v.elem(j); 

return 
r; 

Это вполне естественное решение, но оно может оказаться очень неэффективным. При каждом вызове 
multiply() функция elem() будет вызываться 4*(1+4*3) раз. Если в elem() проводится настоящий контроль 
границ массива, то на такой контроль будет потрачено значительно больше времени, чем на 
выполнение самой функции, и в результате она окажется непригодной для пользователей. С другой 
стороны, если elem() есть некий специальный вариант доступа без контроля, то тем самым мы 
засоряем интерфейс с вектором и матрицей особой функцией доступа, которая нужна только для 
обхода контроля. 
Если можно было бы сделать multiply членом обоих классов vector и matrix, мы могли бы обойтись без 
контроля индекса при обращении к элементу матрицы, но в то же время не вводить специальной 
функции elem(). Однако, функция не может быть членом двух классов. Надо иметь в языке возможность 
предоставлять функции, не являющейся членом, право доступа к частным членам класса. Функция - не 
член класса, - имеющая доступ к его закрытой части, называется другом этого класса. Функция может 
стать другом класса, если в его описании она описана как friend (друг). Например: 
class matrix; 
class vector { 
float 
v[4]; 
// 
... 
friend vector multiply(const matrix&, const vector&); 
}; 
class matrix { 
vector 
v[4]; 
// 
... 
friend vector multiply(const matrix&, const vector&); 


Бьерн Страуструп.
Язык программирования С++ 
 
136 
}; 
Функция-друг не имеет никаких особенностей, за исключением права доступа к закрытой части класса. 
В частности, в такой функции нельзя использовать указатель this, если только она действительно не 
является членом класса. Описание friend является настоящим описанием. Оно вводит имя функции в 
область видимости класса, в котором она была описана, и при этом происходят обычные проверки на 
наличие других описаний такого же имени в этой области видимости. Описание friend может находится 
как в общей, так и в частной частях класса, это не имеет значения. 
Теперь можно написать функцию multiply, используя элементы вектора и матрицы непосредственно: 
vector multiply(const matrix& m, const vector& v) 

vector 
r; 
for (int i = 0; i<3; i++) { // r[i] = m[i] * v; 
r.v[i] = 0; 
for ( int j = 0; j<3; j++) 
r.v[i] 
+=m.v[i][j] 

v.v[j]; 

return 
r; 

Отметим, что подобно функции-члену дружественная функция явно описывается в описании класса, с 
которым дружит. Поэтому она является неотъемлемой частью интерфейса класса наравне с функцией-
членом. 
Функция-член одного класса может быть другом другого класса: 
class x { 
// 
... 
void 
f(); 
}; 
class y { 
// 
... 
friend void x::f(); 
}; 
Вполне возможно, что все функции одного класса являются друзьями другого класса. Для этого есть 
краткая форма записи: 
class x { 
friend class y; 
// 
... 
}; 
В результате такого описания все функции-члены y становятся друзьями класса x. 


Достарыңызбен бөлісу:
1   ...   102   103   104   105   106   107   108   109   ...   256




©emirsaba.org 2024
әкімшілігінің қараңыз

    Басты бет