Ответ 1
friend inline bool operator==(MonitorObjectString& lhs, MonitorObjectString& rhs) {
return(lhs.fVal==rhs.fVal);
}
называется friend definition
. Он определит функцию как функцию, не являющуюся членом пространства имен, окружающего класс, в котором он появляется. Фактически, встроенный избыток: он неявно объявляется встроенным, если это определение друга. Некоторые плюсы и минусы:
- Это делает оператор не видимым для обычного поиска. Единственный способ, которым вы можете это назвать, - использовать зависимый от аргументов поиск. Это приведет к тому, что пространство имен будет свободным от многих объявлений операторов, видимых нормально. Обратите внимание, что это также отключит возможность вызова его с помощью неявных преобразований в MonitorObjectString (поскольку, если оба типа аргументов не совпадают во время поиска кандидатов, которые будут вызваны, зависящий от аргументов поиск не найдет функцию).
- Поиск имен начинается в области класса, в котором появляется определение друга. Это означает, что длинные имена типов или другие имена не должны быть выписаны. Просто отсылайте их так же, как и к нормальной функции-члену класса.
- Так как это друг, функция видит внутренности
MonitorObjectString
. Но это ни хорошо, ни плохо. Это зависит от ситуации. Например, если есть функцииgetFVal()
, что делает функцию friend довольно бессмысленной. Может использоватьgetFVal
как-то тогда.
Мне нравился стиль определения этого друга операторов, потому что они имеют прямой доступ к членам класса и появляются в определении класса, поэтому я мог бы "все с одним взглядом". Однако в последнее время я пришел к выводу, что это не всегда хорошая идея. Если вы можете (и вы должны) реализовать оператор, используя только публичные функции-члены класса, вы должны сделать его оператором non-friend (и не членом), определенным в том же пространстве имен класса. Он гарантирует, что если вы измените какую-либо реализацию, но сохраните интерфейс класса одинаковым - оператор все равно будет работать, и у вас будет меньше каскадных изменений, потому что вы знаете, что он не может получить доступ к деталям реализации.
Тем не менее, я предпочитаю этот стиль над написанием операторов-членов, потому что функции-операторы в области пространства имен имеют дополнительные особенности симметричного с их аргументами: они не обрабатывают специальную функцию слева, потому что обе стороны являются просто нормальными аргументами, а не объектные аргументы, привязанные к *this
. Если либо левая, либо правая сторона относится к типу вашего класса, другая сторона может быть неявно преобразована - независимо от того, слева или справа. Для функций, которые также определены без синтаксиса определения друга (традиционно, в области пространства имен), у вас будет функция выборочного включения заголовков, которые делают эти операторы доступными или нет.