这是基本的问题,是有一个“正确”的方式来实现operator<<
? 阅读这个我可以看到这样的:
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)
其中段落的字符串。
这里的问题是你的,你的文章的解释联系起来 。
这篇文章是关于即具有正确定义布尔关系运营商的问题别人。
运营商:
因为它们比较两个同类型的对象,这些运营商应该返回一个布尔值。 它通常是最简单的定义这些运营商为类的一部分。 这是因为,一类是自动的本身就是一个朋友,所以类型的段落对象可以考察对方(甚至每个人的私有成员)。
还有制造这些独立的功能这让自动转换转换双方如果他们是不是同一类型,而成员函数只允许RHS进行自动转换参数。 我觉得这是因为你真的不希望自动转换在第一时间(通常情况下)发生纸人的说法。 但如果这是你想要的东西(我不建议这样做),然后进行比较独立可能是有利的。
流运算符:
当使用这些作为物流运营商(而不是二进制移位)的第一个参数是一个流。 既然你没有访问流对象(它不是你的修改),他们必须是外部类,这些不能成员运营商。 因此,他们必须是类的朋友或访问一个公共的方法,将做流为您服务。
这也是传统的这些对象的引用返回流对象,所以你可以链接流操作在一起。
#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;
}
你不能做到这一点作为一个成员函数,因为隐含this
参数是的左侧<<
-运算符。 (因此,你需要将其添加为一个成员函数的ostream
-class。不太好:)
你会做得一样没有自由函数friend
荷兰国际集团呢? 这就是我喜欢,因为它清楚地表明,这是一个集成ostream
,而不是你的类的核心功能。
如果可能的话,非会员和非友元函数。
正如香草萨特和Scott Meyers的描述,喜欢非朋友非成员函数到成员函数,以帮助提高封装。
在某些情况下,如C ++流,你不会有选择,而且必须使用非成员函数。
但尽管如此,这并不意味着你必须让你的类的这些功能的朋友:这些功能通过你的类存取仍然可以接取你的类。 如果您在书面方式这些功能这种方式取得成功,那么你就赢了。
关于运营商<<和>>原型
我相信你在你的问题给出了例子是错误的。 例如;
ostream & operator<<(ostream &os) {
return os << paragraph;
}
我甚至不能开始思考了这个方法在流工作。
下面是实现<<和>>经营两种方式。
比方说,你要使用类型T的流状物体
而这要提取/从/插入入T您类型的段落对象的相关数据。
通用运算符<<和>>函数原型
第一个是作为功能:
// 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 ;
}
通用运算符<<和>>方法原型
第二个是为方法:
// 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 ;
}
注意,要使用这个符号,你必须扩展T的类的声明。 对于STL的对象,这是不可能的(你不应该对其进行修改......)。
如果T是什么C ++流?
这里是相同的<<与>>运营商C ++流的原型。
对于通用basic_istream和basic_ostream
请注意,是流的情况下,因为你不能修改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 ;
}
对于焦炭istream和ostream的
下面的代码将只能用于基于字符流。
// 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 ;
}
里斯Ulerich评论有关的事实,基于字符代码不过是它上面的通用代码的“专业化”。 当然,里斯是正确的:我不建议使用基于炭的例子。 这是因为它更简单阅读只在这里给出。 由于它是唯一可行的,如果你只使用基于字符流工作,你应该避免它的平台上,其中wchar_t的代码是常见的(即在Windows上)。
希望这会有所帮助。
应当实现为一个自由,非好友的功能,尤其是如果像大多数事情一样,这些天,输出主要用于诊断和记录。 添加常量存取所有需要进入输出,然后让输出器只需要调用那些做格式化的东西。
其实我已经采取了收集所有这些ostream的输出免费功能于一身的“ostreamhelpers”头文件和实现文件,它保存一个次要功能远离班的真正目的。
签名:
bool operator<<(const obj&, const obj&);
似乎是相当可疑的,这不符合stream
,所以它看起来像运算符重载滥用的情况下约定,也不是按位惯例, operator <
应该返回bool
但operator <<
也许应该返回别的东西。
如果你的意思是这么说的:
ostream& operator<<(ostream&, const obj&);
然后,因为你不能添加函数ostream
必然的功能必须是无功能,无论是friend
还是不取决于它是否具有访问(如果它不需要访问私有或受保护的成员有没有必要让朋友)。
刚刚完成的缘故,我想补充一点,你的确可以创建一个运营商ostream& operator << (ostream& os)
在类中,它可以工作。 从我知道这不是一个好主意,使用它,因为它是非常令人费解和直观。
假设我们有这样的代码:
#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;
}
所以总结起来 - 你可以做到这一点,但你很可能不应该:)
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;
}
输出:100你好你好100按任意键继续......
这可能是一个朋友的功能,只是因为对象是对右手边operator<<
和论证cout
是在左侧。 所以这不可能是一个成员函数的类,它只能是一个朋友的功能。
朋友运算符=平等的权利类
friend std::ostream& operator<<(std::ostream& os, const Object& object) {
os << object._atribute1 << " " << object._atribute2 << " " << atribute._atribute3 << std::endl;
return os;
}