100

#include "logic.h"
...

class A
{
friend ostream& operator<<(ostream&, A&);
...
};

逻辑.cpp

#include "a.h"
...
ostream& logic::operator<<(ostream& os, A& a)
{
...
}
...

当我编译时,它说:

std::ostream& logic::operator<<(std::ostream&, A&)' 必须只取一个参数。

问题是什么?

4

6 回答 6

143

问题是你在类中定义它,它

a) 表示第二个参数是隐含的 ( this) 并且

b)它不会做你想做的事,即 extend std::ostream

您必须将其定义为自由函数:

class A { /* ... */ };
std::ostream& operator<<(std::ostream&, const A& a);
于 2012-05-24T20:28:53.573 回答
52

友元函数不是成员函数,所以问题是您声明operator<<为 的友元A

 friend ostream& operator<<(ostream&, A&);

然后尝试将其定义为类的成员函数logic

 ostream& logic::operator<<(ostream& os, A& a)
          ^^^^^^^

您是否对logic是类还是命名空间感到困惑?

该错误是因为您尝试定义一个带有operator<<两个参数的成员,这意味着它需要三个参数,包括隐式this参数。运算符只能接受两个参数,因此当您编写a << b两个参数时是ab

您想定义ostream& operator<<(ostream&, const A&)为非成员函数,绝对不是成员,logic因为它与该类无关!

std::ostream& operator<<(std::ostream& os, const A& a)
{
  return os << a.number;
}
于 2012-05-24T21:13:52.957 回答
3

我遇到了模板类的这个问题。这是我必须使用的更通用的解决方案:

template class <T>
class myClass
{
    int myField;

    // Helper function accessing my fields
    void toString(std::ostream&) const;

    // Friend means operator<< can use private variables
    // It needs to be declared as a template, but T is taken
    template <class U>
    friend std::ostream& operator<<(std::ostream&, const myClass<U> &);
}

// Operator is a non-member and global, so it's not myClass<U>::operator<<()
// Because of how C++ implements templates the function must be
// fully declared in the header for the linker to resolve it :(
template <class U>
std::ostream& operator<<(std::ostream& os, const myClass<U> & obj)
{
  obj.toString(os);
  return os;
}

现在: * 我的 toString() 函数如果要隐藏在 cpp 中,则不能内联。* 你在标题中遇到了一些代码,我无法摆脱它。* 运算符将调用 toString() 方法,它不是内联的。

operator<< 的主体可以在friend 子句中或在类外声明。两种选择都很丑。:(

也许我误解或遗漏了一些东西,但只是前向声明操作员模板不会链接到 gcc。

这也有效:

template class <T>
class myClass
{
    int myField;

    // Helper function accessing my fields
    void toString(std::ostream&) const;

    // For some reason this requires using T, and not U as above
    friend std::ostream& operator<<(std::ostream&, const myClass<T> &)
    {
        obj.toString(os);
        return os;
    }
}

如果您使用未模板化的父类来实现 operator<<,并使用虚拟 toString() 方法,我认为您还可以避免强制在标头中声明的模板问题。

于 2017-06-23T02:27:18.030 回答
0

如果您定义operator<<为成员函数,它将具有与使用非成员不同的分解语法operator<<。非成员operator<<是二元运算符,其中成员operator<<是一元运算符。

// Declarations
struct MyObj;
std::ostream& operator<<(std::ostream& os, const MyObj& myObj);

struct MyObj
{
    // This is a member unary-operator, hence one argument
    MyObj& operator<<(std::ostream& os) { os << *this; return *this; }

    int value = 8;
};

// This is a non-member binary-operator, 2 arguments
std::ostream& operator<<(std::ostream& os, const MyObj& myObj)
{
    return os << myObj.value;
}

所以....你怎么称呼他们?运算符在某些方面很奇怪,我会挑战你operator<<(...)在头脑中编写语法以使事情有意义。

MyObj mo;

// Calling the unary operator
mo << std::cout;

// which decomposes to...
mo.operator<<(std::cout);

或者您可以尝试调用非成员二元运算符:

MyObj mo;

// Calling the binary operator
std::cout << mo;

// which decomposes to...
operator<<(std::cout, mo);

当你把这些运算符变成成员函数时,你没有义务让它们表现得直观,如果你愿意,你可以定义operator<<(int)左移一些成员变量,理解人们可能有点措手不及,不管你有多少评论写。

几乎最后,有时操作员呼叫的两种分解都有效,您可能会在这里遇到麻烦,我们将推迟该对话。

最后,请注意编写一个看起来像二元运算符的一元成员运算符可能是多么奇怪(因为您可以使成员运算符虚拟......也试图不下放并沿着这条路径运行...... )

struct MyObj
{
    // Note that we now return the ostream
    std::ostream& operator<<(std::ostream& os) { os << *this; return os; }

    int value = 8;
};

这种语法现在会激怒许多编码人员......

MyObj mo;

mo << std::cout << "Words words words";

// this decomposes to...
mo.operator<<(std::cout) << "Words words words";

// ... or even further ...
operator<<(mo.operator<<(std::cout), "Words words words");

请注意cout这里链中的第二个参数是如何......奇怪的吧?

于 2019-09-26T19:37:24.617 回答
0

运算符重载包括成员函数重载和非成员函数重载,不能混用。https://condor.depaul.edu/ntomuro/courses/262/notes/lecture3.html

于 2021-03-25T14:59:09.313 回答
0

关键点是定义为友元函数的logic::前面。operator<<

logic::仅在成员函数之前添加。我理解这类似于告诉编译器这个函数是一个成员函数并授予它相应的权限(例如访问私有函数)。

换句话说,正如@asaelr 和@Morteza 所提到的,“在定义友元函数时,您不要使用类的名称来限定友元函数的名称”。

因此,我们应该删除logic::before operator<<

于 2021-10-21T14:00:53.893 回答