应该运算符<< 是作为友元函数还是作为成员函数来实现?
这基本上就是问题,是否有一种“正确”的方法来实现operator<<? 阅读 this 我可以看到类似:
friend bool operator<<(obj const& lhs, obj const& rhs);
优于类似的东西
ostream& operator<<(obj const& rhs);
但我不太明白我为什么要使用其中之一。
我个人的情况是:
friend ostream & operator<<(ostream &os, const Paragraph& p) {
return os << p.to_str();
}
但我可能会这样做:
ostream & operator<<(ostream &os) {
return os << paragraph;
}
我应该基于什么理由做出这个决定?
注意:
Paragraph::to_str = (return paragraph)
其中段落是一个字符串。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
这里的问题在于您对链接的文章的解释。
平等
这篇文章是关于有人在正确定义布尔关系运算符时遇到问题的。
运算符:
这些运算符应返回布尔值,因为它们正在比较相同类型的两个对象。 将这些运算符定义为类的一部分通常是最简单的。 这是因为类自动成为其自身的友元,因此 Paragraph 类型的对象可以相互检查(甚至彼此的私有成员)。
对于创建这些独立函数有一个争论,因为这可以让自动转换在双方类型不同时进行转换,而成员函数只允许自动转换 rhs。 我发现这是一个纸上谈兵的论点,因为你真的不希望自动转换首先发生(通常)。 但如果这是您想要的(我不推荐),那么使比较器独立式可能会更有利。
Streaming
流操作符:
当您将它们用作流运算符(而不是二进制移位)时,第一个参数是流。 由于您无权访问流对象(您不能修改),这些不能是成员运算符,它们必须位于类的外部。 因此,他们必须是类的朋友,或者有权访问将为您进行流处理的公共方法。
这些对象通常返回对流对象的引用,以便您可以将流操作链接在一起。
The problem here is in your interpretation of the article you link.
Equality
This article is about somebody that is having problems correctly defining the bool relationship operators.
The operator:
These operators should return a bool as they are comparing two objects of the same type. It is usually easiest to define these operators as part of the class. This is because a class is automatically a friend of itself so objects of type Paragraph can examine each other (even each others private members).
There is an argument for making these free standing functions as this lets auto conversion convert both sides if they are not the same type, while member functions only allow the rhs to be auto converted. I find this a paper man argument as you don't really want auto conversion happening in the first place (usually). But if this is something you want (I don't recommend it) then making the comparators free standing can be advantageous.
Streaming
The stream operators:
When you use these as stream operators (rather than binary shift) the first parameter is a stream. Since you do not have access to the stream object (its not yours to modify) these can not be member operators they have to be external to the class. Thus they must either be friends of the class or have access to a public method that will do the streaming for you.
It is also traditional for these objects to return a reference to a stream object so you can chain stream operations together.
您不能将其作为成员函数来执行,因为隐式
this
参数位于<<
运算符的左侧。 (因此,您需要将其作为成员函数添加到ostream
类中。不好:)您能否将其作为一个自由函数而不对其进行
friend
处理? 这就是我更喜欢的,因为它清楚地表明这是与 ostream 的集成,而不是您的类的核心功能。You can not do it as a member function, because the implicit
this
parameter is the left hand side of the<<
-operator. (Hence, you would need to add it as a member function to theostream
-class. Not good :)Could you do it as a free function without
friend
ing it? That's what I prefer, because it makes it clear that this is an integration withostream
, and not a core functionality of your class.如果可能的话,作为非成员和非好友功能。
正如 Herb Sutter 和 Scott Meyers 所描述的,与成员函数相比,更喜欢非友元非成员函数,以帮助提高封装性。
在某些情况下,例如 C++ 流,您没有选择,必须使用非成员函数。
但是,这并不意味着您必须使这些函数成为您的类的朋友:这些函数仍然可以通过您的类访问器访问您的类。 如果你成功地以这种方式编写了这些函数,那么你就赢了。
关于运算符<< 和>> 原型
我相信你在问题中给出的例子是错误的。 例如;
我什至无法开始思考这种方法如何在流中工作。
以下是实现<<的两种方法: 和>> 运营商。
假设您想要使用 T 类型的类似流的对象。
并且您想要从 T 中提取/插入 Paragraph 类型对象的相关数据。
通用运算符 << 和>> 函数原型
第一个是函数:
泛型运算符 << 和>> 方法原型
第二种是作为方法:
请注意,要使用此表示法,您必须扩展 T 的类声明。 对于 STL 对象,这是不可能的(你不应该修改它们......)。
如果 T 是 C++ 流怎么办?
以下是相同<<的原型。 和>> C++ 流的运算符。
对于通用 basic_istream 和 basic_ostream
请注意,这是流的情况,因为您无法修改 C++ 流,所以您必须实现这些函数。 这意味着:
对于 char istream 和 ostream
以下代码仅适用于基于 char 的流。
Rhys Ulerich 评论了基于字符的代码只是其之上的通用代码的“专业化”这一事实。 当然,Rhys 是对的:我不建议使用基于字符的示例。 之所以在这里给出,是因为它更容易阅读。 由于它仅在您仅使用基于字符的流时才可行,因此您应该在 wchar_t 代码常见的平台(即在 Windows 上)上避免使用它。
希望这会有所帮助。
If possible, as non-member and non-friend functions.
As described by Herb Sutter and Scott Meyers, prefer non-friend non-member functions to member functions, to help increase encapsulation.
In some cases, like C++ streams, you won't have the choice and must use non-member functions.
But still, it does not mean you have to make these functions friends of your classes: These functions can still acess your class through your class accessors. If you succeed in writting those functions this way, then you won.
About operator << and >> prototypes
I believe the examples you gave in your question are wrong. For example;
I can't even start to think how this method could work in a stream.
Here are the two ways to implement the << and >> operators.
Let's say you want to use a stream-like object of type T.
And that you want to extract/insert from/into T the relevant data of your object of type Paragraph.
Generic operator << and >> function prototypes
The first being as functions:
Generic operator << and >> method prototypes
The second being as methods:
Note that to use this notation, you must extend T's class declaration. For STL objects, this is not possible (you are not supposed to modify them...).
And what if T is a C++ stream?
Here are the prototypes of the same << and >> operators for C++ streams.
For generic basic_istream and basic_ostream
Note that is case of streams, as you can't modify the C++ stream, you must implement the functions. Which means something like:
For char istream and ostream
The following code will work only for char-based streams.
Rhys Ulerich commented about the fact the char-based code is but a "specialization" of the generic code above it. Of course, Rhys is right: I don't recommend the use of the char-based example. It is only given here because it's simpler to read. As it is only viable if you only work with char-based streams, you should avoid it on platforms where wchar_t code is common (i.e. on Windows).
Hope this will help.
它应该作为免费的、非友元函数来实现,特别是如果像现在的大多数事情一样,输出主要用于诊断和日志记录。 为所有需要进入输出的内容添加 const 访问器,然后让输出器调用它们并进行格式化。
实际上,我已经开始在“ostreamhelpers”标头和实现文件中收集所有这些 ostream 输出自由函数,它使辅助功能远离类的真正用途。
It should be implemented as a free, non-friend functions, especially if, like most things these days, the output is mainly used for diagnostics and logging. Add const accessors for all the things that need to go into the output, and then have the outputter just call those and do formatting.
I've actually taken to collecting all of these ostream output free functions in an "ostreamhelpers" header and implementation file, it keeps that secondary functionality far away from the real purpose of the classes.
签名:
似乎相当可疑,这不符合
stream
约定,也不符合按位约定,因此看起来像是运算符重载滥用的情况,operator <
应该返回bool
但operator <<
可能应该返回其他内容。如果你的意思是这样说:
那么既然你不能向
ostream
添加函数,那么该函数必须是一个自由函数,它是否是friend
取决于它是什么必须访问(如果不需要访问私有或受保护的成员,则无需将其设为好友)。The signature:
Seems rather suspect, this does not fit the
stream
convention nor the bitwise convention so it looks like a case of operator overloading abuse,operator <
should returnbool
butoperator <<
should probably return something else.If you meant so say:
Then since you can't add functions to
ostream
by necessity the function must be a free function, whether it afriend
or not depends on what it has to access (if it doesn't need to access private or protected members there's no need to make it friend).为了完整起见,我想补充一点,您确实可以创建一个运算符
ostream& 运算符 << (ostream& os)
在一个类中,它可以工作。 据我所知,使用它不是一个好主意,因为它非常复杂且不直观。假设我们有这段代码:
所以总结一下 - 你可以做到,但你很可能不应该:)
Just for completion sake, I would like to add that you indeed can create an operator
ostream& operator << (ostream& os)
inside a class and it can work. From what I know it's not a good idea to use it, because it's very convoluted and unintuitive.Let's assume we have this code:
So to sum it up - you can do it, but you most probably shouldn't :)
我建议将
operator<<
定义为私人好友,又名 隐藏好友,以便只能通过依赖于参数的查找来找到它:隐藏的朋友有很多好处,最重要的是它不会污染重载集,可以加快编译速度并改进诊断。 它还可以防止不需要的隐式转换。
I would recommend defining
operator<<
as a private friend aka hidden friend so that it is only found via the argument-dependent lookup:Hidden friends have a number of benefits, most importantly it won't pollute the overload set which can speed up compilation and improve diagnostics. It also prevents undesirable implicit conversions.
友元运算符 = 与类平等的权利
friend operator = equal rights as class
operator<<
作为友元函数实现:这只能是友元函数,因为对象位于运算符<< 的右侧,而参数
cout
位于左侧。 所以这不能是类的成员函数,它只能是友元函数。operator<<
implemented as a friend function:This can be a friend function only because the object is on the right hand side of
operator<<
and argumentcout
is on the left hand side. So this can't be a member function to the class, it can only be a friend function.