Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КРАТКИЙ ОБЗОР С.doc
Скачиваний:
1
Добавлен:
26.10.2018
Размер:
2.11 Mб
Скачать

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&);       };       Функция-друг не имеет никаких особенностей, за исключением права       доступа к закрытой части класса. В частности, в такой функции       нельзя использовать указатель 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.