Raf*_*ini 30 c++ operator-overloading
在一些书籍中,经常在互联网上,我看到像" operator==应该被宣布为朋友"这样的建议.
当运营商必须被宣布为朋友以及何时应该被宣布为会员时,我应该如何理解?除了==和之外,最常需要被宣布为朋友的运营商是什么<<?
Chr*_*ick 40
这实际上取决于一个类是否会在调用operator==(或其他运算符)的左侧或右侧.如果一个类将是对的右侧表达,并且不提供的隐式转换为可以用左手进行比较的型面,你需要实现operator==作为一个单独的函数或作为friend的班级.如果运算符需要访问私有类数据,则必须将其声明为a friend.
例如,
class Message {
std::string content;
public:
Message(const std::string& str);
bool operator==(const std::string& rhs) const;
};
Run Code Online (Sandbox Code Playgroud)
允许您将消息与字符串进行比较
Message message("Test");
std::string msg("Test");
if (message == msg) {
// do stuff...
}
Run Code Online (Sandbox Code Playgroud)
但不是相反
if (msg == message) { // this won't compile
Run Code Online (Sandbox Code Playgroud)
你需要operator==在课堂上宣布一个朋友
class Message {
std::string content;
public:
Message(const std::string& str);
bool operator==(const std::string& rhs) const;
friend bool operator==(const std::string& lhs, const Message& rhs);
};
Run Code Online (Sandbox Code Playgroud)
或者将隐式转换运算符声明为适当的类型
class Message {
std::string content;
public:
Message(const std::string& str);
bool operator==(const std::string& rhs) const;
operator std::string() const;
};
Run Code Online (Sandbox Code Playgroud)
或声明一个单独的函数,如果它不访问私有类数据,则不需要是朋友
bool operator==(const std::string& lhs, const Message& rhs);
Run Code Online (Sandbox Code Playgroud)
Ale*_*ler 19
当您在类外部使用运算符时,两个参数都可以参与隐式类型转换(而在类主体中定义运算符时,只有右侧操作数可以).一般情况下,这对所有的经典二进制运营商的利益(即==,!=,+,-,<<,...).
当然friend,如果您需要,您应该只声明您的类的运算符,而不是仅仅基于该类的公共成员计算其结果.
通常,只有实现为真正需要访问其操作的类的私有或受保护数据的自由函数的运算符才应被声明为朋友,否则它们应该只是非朋友非成员函数.
通常,我作为成员函数实现的唯一运算符是那些基本上不对称的操作符,而操作数不具有相同的角色.我倾向于实现作为成员的是那些作为成员需要:简单的赋值,(),[]和->与复合赋值运算符,一元运算符也许的某些重载在一起<<并>>为它们本身的流或流状类的类.我从不超载&&,||或,.
我倾向于将所有其他运算符实现为自由函数,最好使用它们所操作的类的公共接口,仅在必要时回退为朋友.
保持运营商如!=,==,<,+,/,等作为非成员函数使左和右操作数相对于隐式转换序列,其有助于减少令人惊讶的不对称的数目的相同的处理.
没有人提到hidden friends idiom我怀疑这就是书里的意思。
长版: https: //www.justsoftwaresolutions.co.uk/cplusplus/hidden-friends.html
简洁版本:
大多数情况下,运算符是通过 ADL(参数相关查找)找到的。这就是当您不在命名空间中时找到inoperator==定义的方式。std::stringstdstd
操作员常见的问题之一是巨大的过载集。如果您尝试使用operator<<不可打印的内容,您经常会在错误消息中看到这一点。
因此,如果您operator==直接在包含该类的命名空间中声明,它会起作用,但它也会参与该命名空间中的所有重载解析,这会减慢编译速度并给您带来更多错误噪音。
介绍隐藏的朋友:
struct X {
friend bool operator==(const X& x, const X& y) {...}
};
Run Code Online (Sandbox Code Playgroud)
仅operator==当操作数之一的类型为 时,才会考虑重载决策X。在所有其他情况下,它不会被看到,因此您的编译速度会更快,错误消息也会更好。
这同样适用于所有两个操作数运算符,例如operator<<以及用于 ADL 的其他函数,例如swap.
我总是这样定义我的操作符,现在很多人都认为这是一个很好的做法。
唯一的缺点是——没有很好的方法来定义它。您可能需要考虑分派到某些私人职能。或者您可以这样做: https: //godbolt.org/z/hMarb4 - 但这意味着至少在一个 cpp 文件中将operator==参与正常查找。