【问题标题】:Friend function defining an ostream operator定义 ostream 运算符的友元函数
【发布时间】:2015-10-11 11:52:15
【问题描述】:

我想定义一个 ostream 运算符,让我轻松输出alglib::complex 类型的变量。为了提供一个不包括 alglib 库的工作示例,我将在下面重载 complex<double> 的输出(由于问题的早期版本,此澄清)。在头文件“my_class.h”中我有

using namespace std;
#include <complex>
#include <iostream>

class my_class {

    public:

    ostream& operator << (std::ostream& os, complex<double> a) {
        os << "(" << real(a) << "," << imag(a) << ")";
        return os;
    }

    void output(complex<double>);

    my_class() {}
    ~my_class() {}
};

在源文件“my_class.cpp”中我有

#include "my_class.h"

void my_class::output(complex<double> cd) {
    cout << cd << endl;
}

最后我有一个主方法文件“run_my_class.cpp”:

#include "my_class.h"

int main(int argc, const char* argv[]) {

    my_class obj;
    complex<double> cd=complex<double>(1.0,-1.0);
    obj.output(cd);

}

我尝试编译使用

g++ -c my_class.cpp

但这给了我错误

my_class.h:9:62: error: ‘std::ostream& my_class::operator<<(std::ostream&, std::complex<double>)’ must take exactly one argument
 ostream& operator << (std::ostream& os, complex<double> a) {

但是,如果我将运算符定义为朋友,即friend ostream&amp; operator &lt;&lt; (std::ostream&amp; os, complex&lt;double&gt; a),它会编译并且我编译 main 方法:

g++ run_my_class.cpp my_class.o -o run_my_class

它可以正常工作。然而,这似乎不是 friend 关键字的用途。有没有更好的方法来完成这项工作?

【问题讨论】:

  • 为什么要让输出运算符成为my_class 类的朋友?你甚至没有在函数中使用my_class
  • 这个错误听起来好像没有为参数找到可行的operator &lt;&lt;,而是使用了免费的右值引用转发器operator&lt;&lt; (basic_ostream&lt;..&gt;&amp;&amp;, T const&amp;)。请提供具有适当上下文的MCVE
  • @JoachimPileborg 这样该类就可以使用 ostream 运算符。没有friend,我无法编译它。但也许有更好的方法?
  • 反之亦然:如果函数使用类的私有成员,则必须声明类的函数friend
  • 如果您向我们展示原始问题可能会有所帮助

标签: c++ class operators friend ostream


【解决方案1】:

由于operator &lt;&lt; 将在std::ostream 上调用,因此您不能将此过程定义为my_class成员函数,您必须将其定义为全局函数,因为它是针对std::ostream 的操作,而不是my_class

通过将friend 关键字放入声明中,您的意思是要将operator &lt;&lt; 声明为友元全局函数(不是成员函数!)。 C++ 标准允许您将友元函数的定义放在那里,但它不会是成员函数。同下,更清楚:

#include <complex>
#include <iostream>

class my_class {

public:

    friend ostream& operator << (std::ostream& os, complex<double> a);

    void output(complex<double>);

    my_class() {}
    ~my_class() {}
};

std::ostream& operator << (std::ostream& os, complex<double> a) {
    os << "(" << real(a) << "," << imag(a) << ")";
    return os;
}

正如 cmets 中已经指出的,这里不需要使用 friend

与问题无关,但请注意,在头文件中解析命名空间通常是一个非常糟糕的主意,因为包括它在内的所有其他文件也会隐式解析该命名空间。从长远来看,它很容易导致令人烦恼的编译错误。

【讨论】:

  • 您对“方法”和“函数”表达方式的使用不符合官方 C++ 术语。正确的是“成员函数”和“全局函数”。使用“函数”这个词,就好像它没有(也)指代成员函数一样,尤其容易误导和混淆。 “方法”是成员函数的非正式使用同义词。
  • @ChristianHackl 感谢您的评论,我修改了我的答案。尽管我仍然认为方法和函数之间的区别不应该让任何人感到困惑,但这些都是通用的 OOP 术语,与具体语言无关。不过,这是一个 C++ 问题,所以你有你的意思。
【解决方案2】:

我不会称之为更好的方式,而是更清晰的方式。

这又是你的流操作符:

ostream& operator << (std::ostream& os, complex<double> a) {
        os << "(" << real(a) << "," << imag(a) << ")";
        return os;
}

它的第一个参数是输出流。由于您无权访问输出流,因此您不能将输出流运算符用作成员函数,除非您将其设为类的朋友。

如果你想避免使用friend,你总是可以将它定义为类外部的函数,这是最常见的方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-05
    • 1970-01-01
    • 2011-03-19
    • 2017-07-26
    • 1970-01-01
    相关资源
    最近更新 更多