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



Pdf көрінісі
бет149/256
Дата11.07.2022
өлшемі2,87 Mb.
#37591
1   ...   145   146   147   148   149   150   151   152   ...   256
7.12 Друзья и члены 
В заключении можно обсудить, когда при обращении в закрытую часть пользовательского типа стоит 
использовать функции-члены, а когда функции-друзья. Некоторые функции, например конструкторы, 
деструкторы и виртуальные функции ($$R.12), обязаны быть членами, но для других есть возможность 
выбора. Поскольку, описывая функцию как член, мы не вводим нового глобального имени, при 
отсутствии других доводов следует использовать функции-члены. 
Рассмотрим простой класс X: 
class X { 
// 
... 
X(int); 
int 
m1(); 
int m2() const; 
friend int f1(X&); 
friend int f2(const X&); 
friend int f3(X); 
}; 
Вначале укажем, что члены X::m1() и X::m2() можно вызывать только для объектов класса X. 
Преобразование X(int) не будет применяться к объекту, для которого вызваны X::m1() или X::m2(): 
void g() 

1.m1(); // ошибка: X(1).m1() не используется 
1.m2(); //
ошибка: X(1).m2() не используется 

Глобальная функция f1() имеет то же свойство ($$4.6.3), поскольку ее параметр - ссылка без 
спецификации const. С функциями f2() и f3() ситуация иная: 
void h() 

f1(1); // ошибка: f1(X(1)) не используется 
f2(1); // нормально: f2(X(1)); 
f3(1); // нормально: f3(X(1)); 



Бьерн Страуструп.
Язык программирования С++ 
 
201 
Следовательно операция, изменяющая состояние объекта класса, должна быть членом или глобальной 
функцией с параметром-ссылкой без спецификации const. Операции над основными типами, которые 
требуют в качестве операндов адреса (=, *, ++ и т.д.), для пользовательских типов естественно 
определять как члены. 
Обратно, если требуется неявное преобразование типа для всех операндов некоторой операции, то 
реализующая ее функция должна быть не членом, а глобальной функцией и иметь параметр типа 
ссылки со спецификацией const или нессылочный параметр. Так обычно обстоит дело с функциями
реализующими операции, которые для основных типов не требуют адресов в качестве операндов (+, -, || 
и т.д.). 
Если операции преобразования типа не определены, то нет неопровержимых доводов в пользу 
функции-члена перед функцией-другом с параметром-ссылкой и наоборот. Бывает, что программисту 
просто одна форма записи вызова нравится больше, чем другая. Например, многим для обозначения 
функции обращения матрицы m больше нравится запись inv(m), чем m.inv(). Конечно, если функция 
inv() обращает саму матрицу m, а не возвращает новую, обратную m, матрицу, то inv() должна быть 
членом. 
При всех прочих равных условиях лучше все-таки остановиться на функции-члене. Можно привести 
такие доводы. Нельзя гарантировать, что когда-нибудь не будет определена операция обращения. 
Нельзя во всех случаях гарантировать, что будущие изменения не повлекут за собой изменения в 
состоянии объекта. Запись вызова функции-члена ясно показывает программисту, что объект может 
быть изменен, тогда как запись с параметром-ссылкой далеко не столь очевидна. Далее, выражения 
допустимые в функции-члене могут быть существенно короче эквивалентных выражений в глобальной 
функции. Глобальная функция должна использовать явно заданные параметры, а в функции-члене 
можно неявно использовать указатель this. Наконец, поскольку имена членов не являются глобальными 
именами, они обычно оказываются короче, чем имен глобальных функций. 


Достарыңызбен бөлісу:
1   ...   145   146   147   148   149   150   151   152   ...   256




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

    Басты бет