在一些书籍中以及互联网上,我看到过像“operator==
应该声明为友元”的建议。
当操作符必须被声明为友元时,应如何理解?什么情况下应将其声明为成员?除了==
和<<
之外,哪些运算符最常需要声明为友元?
在一些书籍中以及互联网上,我看到过像“operator==
应该声明为友元”的建议。
当操作符必须被声明为友元时,应如何理解?什么情况下应将其声明为成员?除了==
和<<
之外,哪些运算符最常需要声明为友元?
operator==
(或其他运算符)的左侧或右侧。如果一个类将出现在表达式的右侧,并且没有提供可与左侧比较的类型的隐式转换,则需要将operator==
实现为单独的函数或该类的friend
。如果该运算符需要访问私有类数据,则必须声明为friend
。class Message {
std::string content;
public:
Message(const std::string& str);
bool operator==(const std::string& rhs) const;
};
允许您将消息与字符串进行比较
Message message("Test");
std::string msg("Test");
if (message == msg) {
// do stuff...
}
if (msg == message) { // this won't compile
你需要在类内声明一个友元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);
};
或者声明到适当类型的隐式转换运算符
class Message {
std::string content;
public:
Message(const std::string& str);
bool operator==(const std::string& rhs) const;
operator std::string() const;
};
bool operator==(const std::string& lhs, const Message& rhs);
friend
声明就足够了(如果您愿意,可以使用内联定义)。 - Mike Seymour如果你把运算符放在类外,两个参数都可以参与隐式类型转换(而如果把运算符定义在类体内,则只有右操作数可以)。总的来说,这对于所有经典二元运算符(如 ==
,!=
, +
, -
, <<
等)都是有益的。
当然,只有当你需要使用运算符对类进行友元声明时才应该这样做,而不是仅基于类的公共成员计算结果。
()
、[]
和->
以及复合赋值运算符、一元运算符和可能是流或类似流类的某些重载的<<
和>>
。我从不重载&&
、||
或,
。!=
、==
、<
、+
、/
等操作符作为非成员函数可以使左右操作数在隐式转换序列方面得到相同的处理,有助于减少惊人的不对称性数量。struct X {
friend bool operator==(const X& x, const X& y) {...}
};
如果操作数之一的类型为X
,则只会考虑重载此operator==
。在其他情况下,它将不会被看到,因此您的编译速度将更快,错误消息也更好。
对于所有两个操作数的运算符,例如operator<<
以及其他旨在进行ADL的函数,如swap
,情况也是如此。
我总是像这样定义我的运算符,现在被相当多的人认为是一个好习惯。
唯一的缺点是-没有很好的方法来定义它。您可能希望将其分派给某些私有函数。或者您可以这样做:https://godbolt.org/z/hMarb4 -但这意味着至少在一个cpp文件中,operator==
将参与正常查找。