-2

对于我的项目,我正在尝试为复数类创建一个免费函数。它在 cpp 文件中定义。该函数是一个重载的输入流操作符,但我不断收到错误

No operator ">>" matches these operands operand types are: std::istream >> double

线上

in >> z.real();
in >> z.imag();

我创建了一个名为的文件complex.h,其中包含complex类和两个我想要工作的重载运算符、复数的构造函数(不确定是否需要但包括在内),以及两个用于检索复杂类的实部和虚部的 getter 方法。这会重现错误。

成员函数的声明由我的项目规范决定。它们的返回类型不能更改。

#pragma once
#include <iostream>
#include <cmath>

class complex {

private://may include private helper functions
    double realX = 0;
    double imaginaryY = 0;

public:// interface for operators and member functions (methods)
    //**********************Constructors***************************
    complex() {}
    complex(double x) {
        realX = x;
    }
    complex(double x, double y) {
        realX = x;
        imaginaryY = y;
    }
    complex(const complex& z) : realX(z.realX), imaginaryY(z.imaginaryY) { //copy constructor
    }
    double real() const {
        return realX;
    }
    double imag() const {
        return imaginaryY;
    }
};

std::istream& operator>>(std::istream& in, complex& z) {
    in >> z.real();
    in >> z.imag();
    return in;
}
std::ostream& operator<<(std::ostream& output, const complex& z) {
    output << "(" << z.real()
        << ", " << z.imag()
        << "i)";
    return output;
}

4

1 回答 1

1
No operator ">>" matches these operands operand types are: std::istream >> double

这似乎是一个奇怪的错误消息。毕竟,人们可以相当快地想出一个示例程序,它可以double从. 那么这里有什么问题呢?std::cinstd::istream

答案出现在此错误消息后面的那一堆注释中。(是的,这可能是一个令人生畏的混乱,但注释可以帮助诊断问题。不,我不希望整个混乱都被复制到问题中,因为它很大而且大部分都不相关。)候选运营商列表中的某处是

operator>>(double& __f)

这是允许流式传输double. 但是,请注意参数的类型——它不是double,而是double&。流的目标必须命名一个变量,而不仅仅是提供一个值。在您的情况下,尝试in >> z.real()类似于尝试in >> 3.1z.real()和的类型3.1都是double,所以你可以对一个做什么,你可以对另一个做什么。希望您不相信可以通过将新值流式传输到3.1. 同样,您不能将值流式传输到返回 a 的函数中double

一种解决方案是让您的函数返回流运算符所期望的内容,如double& real()(添加和号并删除const)。但是,提供对私有成员的公共非常量引用会破坏封装;该成员还不如在那时公开。另外,您的项目不允许这样做。让我们寻找更好的方法。

一个更常见的解决方案是创建operator>>一个friend类,以便它可以设置私有成员。这需要添加行

friend std::istream& operator>>(std::istream& in, complex& z);

到你的类定义。完成后,您的实现operator>>可以访问私有数据成员,绕过访问器功能。注意:operator>>如果需要的话,定义可以在类定义之外保留在原处。

std::istream& operator>>(std::istream& in, complex& z) {
    in >> z.realX;
    in >> z.imaginaryY;
    return in;
}

更迂回的方法使用构造和分配而不是友谊。在更复杂的情况下,这可能会减少代码重复。但是,在您的情况下,它会触发警告,因为您的类通过具有复制构造函数但没有赋值运算符违反了三法则。尽管如此,您的显式复制构造函数是编译器会自动为您生成的。您可以通过注释掉您的复制构造函数来解决警告。

std::istream& operator>>(std::istream& in, complex& z) {
    double real;
    double imaginary;
    
    in >> real;
    in >> imaginary;
    z = complex{real, imaginary};
    
    return in;
}

对于像你的complex课这样简单的事情,我会选择友谊。

于 2020-10-17T17:35:43.087 回答