运算符<<的全局重载不起作用,为什么?

时间:2019-10-01 10:46:36

标签: c++ operator-overloading

我了解到 operator <<< / em> 可以通过使其成为类的好友函数而重载。 例如,

struct Test
{
    std::string d_data;
    Test(const std::string & data) : d_data{data} {}
    friend std::ostream & operator<<(std::ostream & ostr, const Test & obj)
    {
        ostr << obj.d_data << '\n';
        return ostr;
    }
};

int main()
{
    Test t1("one");
    std::cout << t1;
    Test t2("two");
    std::cout << t2;
}
one
two

这似乎按预期工作。

但是,我无法理解为什么同样的方法对于全局重载不起作用。

#include <iostream>
#include <ostream>
#include <string>

std::ostream & operator<<(std::ostream & os, const std::string & s)
{
    os << s << '\n';
    return os;
}

int main()
{
    std::cout << "stackoverflow";
    std::cout << "stackoverflow";
}
  

stackoverflowstackoverflow

期望这些字符串要用换行符分隔,但不能按预期工作。

3 个答案:

答案 0 :(得分:6)

您的运算符使用

std::cout << "stackoverflow";

需要用户定义的转换,类型为const char *的对象(在将字符串文字隐式转换为指向其第一个字符的指针之后)到类型为std::string的对象。

但是标准basic_ostream类已经具有不需要这种转换的运算符

template<class charT, class traits>
basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>&, const char*);

因此将调用此运算符而不是您的运算符。

此外,您的运营商之内

std::ostream & operator<<(std::ostream & os, const std::string & s)
{
    os << s << '\n';
    return os;
}

本身存在递归调用。

您可以通过以下方式定义您的运营商

#include <iostream>
#include <string>

std::ostream & operator<<(std::ostream & os, const char *s)
{
    return std::operator <<( os, s ) << '\n';
}

int main()
{
    std::cout << "stackoverflow";
    std::cout << "stackoverflow";
}

并获得预期的结果

stackoverflow
stackoverflow

答案 1 :(得分:4)

请注意,"stackoverflow"的类型为const char[],而不是std::string。这意味着将不会调用您的重载,而是会调用标准库中的重载(operator<<(std::basic_ostream),因为它是完全匹配的,不需要从const char[]std::string的隐式转换

template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,  
                                        const char* s );

BTW:可能是由于ADL导致的。

答案 2 :(得分:1)

您可以全局重载,但是"stackoverflow"不是std::string,因此不会使用您的。
(而且标准库中已经有这样的重载。)

要查看其效果,请将您的第一个重载移出类定义,并使其成为非好友。
必须将其声明为friend的唯一原因是您已在类定义中声明了它,否则它将成为成员函数。

这将按预期工作:

struct Test
{
    std::string d_data;
    Test(const std::string & data) : d_data{data} {}
};

std::ostream & operator<<(std::ostream & ostr, const Test & obj)
{
    ostr << obj.d_data << '\n';
    return ostr;
}

int main()
{
    Test t1("one");
    std::cout << t1;
    Test t2("two");
    std::cout << t2;
}