C++ operator<< 应该实现为友元函数还是成员函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/236801/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Should operator<< be implemented as a friend or as a member function?
提问by Federico Builes
That's basically the question, is there a "right" way to implement operator<<
?
Reading thisI can see that something like:
这基本上就是问题,是否有“正确”的实施方式operator<<
?阅读本文,我可以看到类似的内容:
friend bool operator<<(obj const& lhs, obj const& rhs);
is preferred to something like
更喜欢类似的东西
ostream& operator<<(obj const& rhs);
But I can't quite see why should I use one or the other.
但我不太明白为什么我应该使用其中一个。
My personal case is:
我的个人情况是:
friend ostream & operator<<(ostream &os, const Paragraph& p) {
return os << p.to_str();
}
But I could probably do:
但我可能会这样做:
ostream & operator<<(ostream &os) {
return os << paragraph;
}
What rationale should I base this decision on?
我应该根据什么理由做出这个决定?
Note:
注意:
Paragraph::to_str = (return paragraph)
where paragraph's a string.
其中段落是一个字符串。
采纳答案by Martin York
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:
运营商:
- Equality == and !=
- Relationship < > <= >=
- 相等 == 和 !=
- 关系 < > <= >=
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).
这些运算符在比较两个相同类型的对象时应该返回一个布尔值。将这些运算符定义为类的一部分通常是最容易的。这是因为一个类自动成为它自己的朋友,所以 Paragraph 类型的对象可以相互检查(甚至相互之间的私有成员)。
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.
有一个关于使这些独立函数的争论,因为如果它们的类型不同,这可以让自动转换转换双方,而成员函数只允许自动转换 rhs。我发现这是一个纸人的论点,因为您并不真正希望首先(通常)发生自动转换。但是如果这是你想要的东西(我不推荐它),那么让比较器独立存在可能是有利的。
Streaming
流媒体
The stream operators:
流操作符:
- operator << output
- operator >> input
- 运算符 << 输出
- 运算符 >> 输入
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.
这些对象返回对流对象的引用也是传统的做法,因此您可以将流操作链接在一起。
#include <iostream>
class Paragraph
{
public:
explicit Paragraph(std::string const& init)
:m_para(init)
{}
std::string const& to_str() const
{
return m_para;
}
bool operator==(Paragraph const& rhs) const
{
return m_para == rhs.m_para;
}
bool operator!=(Paragraph const& rhs) const
{
// Define != operator in terms of the == operator
return !(this->operator==(rhs));
}
bool operator<(Paragraph const& rhs) const
{
return m_para < rhs.m_para;
}
private:
friend std::ostream & operator<<(std::ostream &os, const Paragraph& p);
std::string m_para;
};
std::ostream & operator<<(std::ostream &os, const Paragraph& p)
{
return os << p.to_str();
}
int main()
{
Paragraph p("Plop");
Paragraph q(p);
std::cout << p << std::endl << (p == q) << std::endl;
}
回答by Magnus Hoff
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 the ostream
-class. Not good :)
您不能将其作为成员函数来执行,因为隐式this
参数是<<
-operator的左侧。(因此,您需要将它作为成员函数添加到ostream
-class 中。不好:)
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 with ostream
, and not a core functionality of your class.
你能把它作为一个免费的功能来做而不用friend
它吗?这就是我更喜欢的,因为它清楚地表明这是与 的集成ostream
,而不是类的核心功能。
回答by paercebal
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.
正如 Herb Sutter 和 Scott Meyers 所描述的,比起成员函数,更喜欢非友元非成员函数,以帮助增加封装性。
In some cases, like C++ streams, you won't have the choice and must use non-member functions.
在某些情况下,如 C++ 流,您没有选择权,必须使用非成员函数。
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;
我相信你在问题中给出的例子是错误的。例如;
ostream & operator<<(ostream &os) {
return os << paragraph;
}
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.
假设您想使用类型为 T 的类流对象。
And that you want to extract/insert from/into T the relevant data of your object of type Paragraph.
并且您想从/插入到 T 类型的对象的相关数据。
Generic operator << and >> function prototypes
通用运算符 << 和 >> 函数原型
The first being as functions:
第一个是作为函数:
// T << Paragraph
T & operator << (T & p_oOutputStream, const Paragraph & p_oParagraph)
{
// do the insertion of p_oParagraph
return p_oOutputStream ;
}
// T >> Paragraph
T & operator >> (T & p_oInputStream, const Paragraph & p_oParagraph)
{
// do the extraction of p_oParagraph
return p_oInputStream ;
}
Generic operator << and >> method prototypes
通用运算符 << 和 >> 方法原型
The second being as methods:
第二个是作为方法:
// T << Paragraph
T & T::operator << (const Paragraph & p_oParagraph)
{
// do the insertion of p_oParagraph
return *this ;
}
// T >> Paragraph
T & T::operator >> (const Paragraph & p_oParagraph)
{
// do the extraction of p_oParagraph
return *this ;
}
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...).
请注意,要使用此表示法,您必须扩展 T 的类声明。对于 STL 对象,这是不可能的(您不应该修改它们......)。
And what if T is a C++ stream?
如果 T 是 C++ 流呢?
Here are the prototypes of the same << and >> operators for C++ streams.
以下是 C++ 流的相同 << 和 >> 运算符的原型。
For generic basic_istream and basic_ostream
对于通用 basic_istream 和 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:
请注意,这是流的情况,因为您不能修改 C++ 流,您必须实现这些功能。这意味着:
// OUTPUT << Paragraph
template <typename charT, typename traits>
std::basic_ostream<charT,traits> & operator << (std::basic_ostream<charT,traits> & p_oOutputStream, const Paragraph & p_oParagraph)
{
// do the insertion of p_oParagraph
return p_oOutputStream ;
}
// INPUT >> Paragraph
template <typename charT, typename traits>
std::basic_istream<charT,traits> & operator >> (std::basic_istream<charT,traits> & p_oInputStream, const CMyObject & p_oParagraph)
{
// do the extract of p_oParagraph
return p_oInputStream ;
}
For char istream and ostream
对于 char istream 和 ostream
The following code will work only for char-based streams.
以下代码仅适用于基于字符的流。
// OUTPUT << A
std::ostream & operator << (std::ostream & p_oOutputStream, const Paragraph & p_oParagraph)
{
// do the insertion of p_oParagraph
return p_oOutputStream ;
}
// INPUT >> A
std::istream & operator >> (std::istream & p_oInputStream, const Paragraph & p_oParagraph)
{
// do the extract of p_oParagraph
return p_oInputStream ;
}
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).
Rhys Ulerich 评论说基于字符的代码只是它上面的通用代码的“特殊化”。当然,Rhys 是对的:我不推荐使用基于字符的示例。仅在此处给出,因为它更易于阅读。因为它只有在您只使用基于字符的流时才可行,所以您应该避免在 wchar_t 代码常见的平台上(即在 Windows 上)。
Hope this will help.
希望这会有所帮助。
回答by XPav
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.
它应该作为一个免费的、非友好的函数来实现,特别是如果像现在的大多数事情一样,输出主要用于诊断和日志记录。为需要进入输出的所有内容添加 const 访问器,然后让输出器调用它们并进行格式化。
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.
我实际上已经在“ostreamhelpers”头文件和实现文件中收集所有这些 ostream 输出自由函数,它使次要功能远离类的真正目的。
回答by Motti
The signature:
签名:
bool operator<<(const obj&, const obj&);
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 return bool
but operator <<
should probably return something else.
似乎相当可疑,这不符合stream
约定,也不符合按位约定,因此看起来像是运算符重载滥用的情况,operator <
应该返回bool
但operator <<
可能应该返回其他内容。
If you meant so say:
如果你的意思是这样说:
ostream& operator<<(ostream&, const obj&);
Then since you can't add functions to ostream
by necessity the function must be a free function, whether it a friend
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
,因此该函数必须是一个自由函数,它是否为 afriend
取决于它必须访问的内容(如果它不需要访问私有或受保护的成员,则无需使其成为朋友)。
回答by ashrasmun
Just for completion sake, I would like to add that you indeed cancreate 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.
为了完成起见,我想补充一点,您确实可以ostream& operator << (ostream& os)
在类中创建一个运算符并且它可以工作。据我所知,使用它不是一个好主意,因为它非常复杂且不直观。
Let's assume we have this code:
假设我们有这样的代码:
#include <iostream>
#include <string>
using namespace std;
struct Widget
{
string name;
Widget(string _name) : name(_name) {}
ostream& operator << (ostream& os)
{
return os << name;
}
};
int main()
{
Widget w1("w1");
Widget w2("w2");
// These two won't work
{
// Error: operand types are std::ostream << std::ostream
// cout << w1.operator<<(cout) << '\n';
// Error: operand types are std::ostream << Widget
// cout << w1 << '\n';
}
// However these two work
{
w1 << cout << '\n';
// Call to w1.operator<<(cout) returns a reference to ostream&
w2 << w1.operator<<(cout) << '\n';
}
return 0;
}
So to sum it up - you can do it, but you most probably shouldn't :)
所以总结一下 - 你可以做到,但你很可能不应该:)
回答by Rohit Vipin Mathews
operator<<
implemented as a friend function:
operator<<
实现为友元函数:
#include <iostream>
#include <string>
using namespace std;
class Samp
{
public:
int ID;
string strName;
friend std::ostream& operator<<(std::ostream &os, const Samp& obj);
};
std::ostream& operator<<(std::ostream &os, const Samp& obj)
{
os << obj.ID<< “ ” << obj.strName;
return os;
}
int main()
{
Samp obj, obj1;
obj.ID = 100;
obj.strName = "Hello";
obj1=obj;
cout << obj <<endl<< obj1;
}
OUTPUT:
100 Hello
100 Hello
输出:
100 你好
100 你好
This can be a friend function only because the object is on the right hand side of operator<<
and argument cout
is on the left hand side. So this can't be a member function to the class, it can only be a friend function.
这只能是友元函数,因为对象在右侧operator<<
,参数cout
在左侧。所以 this 不能是类的成员函数,它只能是友元函数。
回答by Nehigienix
friend operator = equal rights as class
友元运算符 = 与类的同等权利
friend std::ostream& operator<<(std::ostream& os, const Object& object) {
os << object._atribute1 << " " << object._atribute2 << " " << atribute._atribute3 << std::endl;
return os;
}