当前位置:  开发笔记 > 编程语言 > 正文

operator <<应该实现为朋友还是成员函数?

如何解决《operator<<应该实现为朋友还是成员函数?》经验,为你挑选了5个好方法。

这基本上就是问题,是否有"正确"的实施方式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) 

其中段落是一个字符串.



1> Martin York..:

这里的问题在于您对所链接文章的解释.

本文是关于正确定义bool关系运算符的问题的人.

运营商:

平等==和!=

关系<> <=> =

这些运算符应该返回一个bool,因为它们正在比较两个相同类型的对象.通常最简单的方法是将这些运算符定义为类的一部分.这是因为类自动成为其自身的朋友,因此Paragraph类型的对象可以相互检查(甚至每个其他私有成员).

有一个参数可以使这些自由站立功能,因为如果它们不是同一类型,则允许自动转换转换双方,而成员函数只允许自动转换rhs.我发现这是一个纸人争论,因为你并不真的希望首先发生自动转换(通常).但如果这是你想要的东西(我不推荐它),那么让比较器自由站立可能是有利的.

流运营商:

operator <<输出

运算符>>输入

当您将这些作为流运算符(而不是二进制移位)使用时,第一个参数是流.由于您无权访问流对象(不是您的修改),因此这些不能是成员运算符,因此它们必须位于类的外部.因此,他们必须是班级的朋友,或者可以访问将为您进行流式传输的公共方法.

这些对象传统上也返回对流对象的引用,因此您可以将流操作链接在一起.

#include 

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;
}


@MattClarkson:不是.它是友元函数声明,因此不属于类,因此不受访问说明符的影响.我通常将友元函数声明放在他们访问的数据旁边.
为什么`operator <<``private:`?
如果您使用公共函数访问数据,为什么它需要是一个友好的函数?对不起,如果问题很愚蠢.
@SemyonDanilov:你为什么要打破封装并添加getter!`freiend`是一种扩展公共接口而不破坏封装的方法.阅读http://programmers.stackexchange.com/a/99595/12917
@LokiAstari但是肯定这是删除to_str或将其设为私有的论据.就目前而言,流媒体运营商不必是朋友,因为它只使用公共功能.

2> Magnus Hoff..:

您不能将其作为成员函数执行,因为隐式this参数是<<-operator 的左侧.(因此,你需要将它作为成员函数添加到ostream-class.不好:)

你可以把它作为一个免费的功能friend吗?这是我更喜欢的,因为它清楚地表明这是与ostream您的类的集成,而不是您的类的核心功能.



3> paercebal..:
如果可能,作为非会员和非朋友功能.

正如Herb Sutter和Scott Meyers所描述的,更喜欢非朋友非成员函数到成员函数,以帮助增加封装.

在某些情况下,如C++流,您将无法选择,必须使用非成员函数.

但是,这并不意味着你必须让这些函数成为你的类的朋友:这些函数仍然可以通过类访问器访问你的类.如果你成功地以这种方式编写这些功能,那么你就赢了.

关于operator <<和>>原型

我相信你在问题中提供的例子是错误的.例如;

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 
std::basic_ostream & operator << (std::basic_ostream & p_oOutputStream, const Paragraph & p_oParagraph)
{
   // do the insertion of p_oParagraph
   return p_oOutputStream ;
}

// INPUT >> Paragraph
template 
std::basic_istream & operator >> (std::basic_istream & p_oInputStream, const CMyObject & p_oParagraph)
{
   // do the extract of p_oParagraph
   return p_oInputStream ;
}

对于char istream和ostream

以下代码仅适用于基于char的流.

// 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评论了这样一个事实,即基于字符的代码只是它上面的通用代码的"特化".当然,Rhys是对的:我不建议使用基于char的例子.它只在这里给出,因为它更容易阅读.因为只有你只使用基于字符串的流才可行,所以你应该在wchar_t代码很常见的平台上(例如在Windows上)避免使用它.

希望这会有所帮助.



4> XPav..:

它应该作为一个免费的,非朋友的功能实现,特别是如果像现在大多数事情一样,输出主要用于诊断和记录.为需要进入输出的所有内容添加const访问器,然后让输出器调用它们并进行格式化.

我实际上已经采取了在"ostreamhelpers"头和实现文件中收集所有这些ostream输出自由函数,它使次要功能远离类的真正目的.



5> Motti..:

签名:

bool operator<<(const obj&, const obj&);

似乎相当可疑,这不符合stream惯例,也不符合按位约定,因此看起来像运算符重载滥用的情况,operator <应该返回booloperator <<应该返回其他内容.

如果你的意思是这样说:

ostream& operator<<(ostream&, const obj&); 

然后,因为你不能添加函数ostream,必要时函数必须是一个自由函数,无论它是否friend依赖于它必须访问的内容(如果它不需要访问私有或受保护的成员,则不需要它朋友).

推荐阅读
家具销售_903
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有