|
Программирование >> Инициализация объектов класса, структура
class String { friend bool operator==( const String s, const String s ); friend bool operator==( const char *, const String s ); friend bool operator==( const String s, const char * ); public: ... остальная часть класса String объявления сразу после заголовка класса: В этих трех строчках три перегруженных оператора сравнения, принадлежащие глобальной области видимости, объявляются друзьями класса String, а следовательно, в / / дружественнхе операторы напрям обращаются к закрыт членам класса String bool operator==( const String sstr1, const String sstr2 ) { if ( str1. size != str2. size ) return false; return strcmp( str1. string, str2. string ) ? false : true; их определениях можно напрямую обращаться к закрытым членам данного класса: inline bool operator==( const String sstr, const char *s ) { return strcmp( str. string, s ) ? false : true; и т . д. Можно возразить, что в данном случае прямой доступ к членам size и string необязателен, так как встроенные функции c str() и size() столь же эффективны и при этом сохраняют инкапсуляцию, а значит, нет особой нужды объявлять операторы равенства для класса String его друзьями. Как узнать, следует ли сделать оператор, не являющийся членом класса, его другом или воспользоваться функциями доступа? В общем случае разработчик должен сократить до минимума число объявленных функций и операторов, которые имеют доступ к внутреннему представлению класса. Если имеются функции доступа, обеспечивающие равную эффективность, то предпочтение следует отдать им, тем самым изолируя операторы в пространстве имен от изменений представления класса, как это делается и для других функций. Если же разработчик класса не предоставляет функций доступа для некоторых членов, а объявленный в пространстве имен оператор должен к этим членам обращаться, то использование механизма друзей становится неизбежным. Альтернативной реализацией является объявление глобальн1х операторов равенства друзьями класса String. Если функция или оператор объявлены таким образом, им предоставляется доступ к неоткрытым членам. Объявление друга (оно начинается с ключевого слова friend) встречается только внутри определения класса. Поскольку друзья не являются членами класса, объявляющего дружественные отношения, то безразлично, в какой из секций - public, private или protected - они объявлены. В примере ниже мы решили поместить все подобные extern ostreams storeCn( ostream s, Screen s ); extern BitMaps storeCn( BitMap s, Screen s ); ... class Screen { friend ostreams storeCn( ostream s, Screen s ); friend BitMaps storeCn( BitMap s, Screen s ); ... он хочет дать неограниченные права доступа: }; Если функция манипулирует объектами двух разных классов и ей нужен доступ к их неоткрытым членам, то такую функцию можно либо объявить другом обоих классов, либо сделать членом одного и другом второго. class Window; это всего объявление class Screen { friend bool is eal( Screen s, Window s ); ... class Window { friend bool is eal( Screen s, Window s ); ... Объявление функции другом двух классов должно выглядеть так: }; Если же мы решили сделать функцию членом одного класса и другом второго, то объявления будут построены следующим образом: Наиболее часто такой механизм применяется для того, чтобы разрешить перегруженным операторам, не являющимся членами класса, доступ к его закрытым членам. Если бы не необходимость обеспечить симметрию левого и правого операндов, то перегруженный оператор был бы функцией-членом с полными правами доступа. Хотя объявления друзей обычно употребляются но отношению к операторам, бывают случаи, когда функцию в пространстве имен, функцию-член другого класса или даже целый класс приходится объявлять таким образом. Если один класс объявлен другом второго, то все функции-члены первого класса получают доступ к неоткрытым членам другого. Рассмотрим это на примере функций, не являющихся операторами. Класс должен объявлять другом каждую из множества перегруженных функций, которой class Window; class Screen { Screen copy() - член класса Screen Screens copy( Window s ); class Window { Screen::copy() - друг класса Window friend Screens Screen::copy( Window s ); Screens Screen::copy( Window s ) { /* ... */ } Функция-член одного класса не может быть объявлена другом второго, пока компилятор не увидел определения ее собственного класса. Это не всегда возможно. Предположим, что Screen должен объявить некоторые функции-члены Window своими друзьями, а Window - объявить таким же образом некоторые функции-члена Screen. В таком случае class Window; class Screen { friend class Window; ... весь класс Window объявляется другом Screen: }; К закрытым членам класса Screen теперь можно обращаться из любой функции-члена Window. Упражнение 15.6 Реализуйте операторы ввода и вывода, определенн1е для класса Screen в упражнении 15.5, в виде друзей и модифицируйте их определения так, чтобы они напрямую обращались к закрытым членам. Какая реализация лучше? Объясните почему. 15.3. Оператор - Присваивание одного объекта другому объекту того же класса выполняется с помощью копирующего оператора присваивания. (Этот специальный случай был рассмотрен в разделе 14.7.) Для класса могут быть определены и другие операторы присваивания. Если объектам класса надо присваивать значения типа, отличного от этого класса, то разрешается определить такие операторы, принимающие подобные параметры. Например, чтобы String car ( Volks ); поддержать присваивание C-строки объекту String: car = Studebaker ;
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |