【问题标题】:Is it possible to overload the ostream operator for arithmetic expressions?是否可以为算术表达式重载 ostream 运算符?
【发布时间】:2013-11-28 21:15:43
【问题描述】:

是否可以为执行算术运算(例如加法)然后输出结果的 ostream 运算符创建重载?可以在整个网络上找到的标准 ostream 重载只能从单个变量流式传输。我需要做以下事情:

std::cout << x+y << std::endl;

甚至更复杂的表达式,例如:

std::cout << x*y+(3*z)^2 << std::endl;

其中 x、y 和 z 是一个简单的定制结构的实例,其中算术运算已经定义(重载)。

编辑:

这是我的代码:

struct scalar //complex scalar data structure
{
friend scalar operator^(const scalar&, int); //integer power operator overload
friend scalar exp(const scalar&); //exponential power function
std::ostream& operator<<(std::ostream&, const scalar&)
protected:
  double re;
  double im;
public:
  double real() {return re;} //returns the real part
  double imag() {return im;} //returns the imaginary part
  scalar(double _re, double _im) {re=_re;im=_im;} //constructor 1
  scalar(double _re) {re=_re;im=0.0;} //constructor 2
  scalar(const scalar& s): re(s.re), im(s.im) {} //copy constructor
  scalar& operator=(const scalar& rhs) //assignment operator overload
  {
    if (&rhs==this) return *this; //checks for self-assignment
    re=rhs.re; //sets real parts equal
    im=rhs.im; //sets imaginary parts equal
    return *this;
  }
  scalar& operator+=(const scalar& rhs) //compound addition-assignment operator overload
  {
    if (&rhs==this) return *this; //checks for self-assignment
    re=re+rhs.re; //adds real parts
    im=im+rhs.im; //adds imaginary parts
    return *this;
  }
  scalar& operator*=(const scalar& rhs) //compound multiplication-assignment operator overload
  {
    if (&rhs==this) return *this; //checks for self-assignment
    double x1=re; double x2=rhs.re; double y1=im; double y2=rhs.im;
    re=x1*x2-y1*y2; //multiplies real parts
    im=x1*y2+x2*y1; //multiplies imaginary parts
    return *this;
  }
  scalar& operator-=(const scalar& rhs) //compound subtraction-assignment operator overload
  {
    if (&rhs==this) return *this; //checks for self-assignment
    re=re-rhs.re; //adds real parts
    im=im-rhs.im; //adds imaginary parts
    return *this;
  }
  scalar& operator/=(const scalar& rhs) //compound division-assignment operator overload
  {
    if (&rhs==this) return *this; //checks for self-assignment
    double x1=re; double x2=rhs.re; double y1=im; double y2=rhs.im;
    double n;
    n =pow(x2,2)+pow(y2,2);
    if (n==0) throw(1);
    re=(x1*x2+y1*y2)/n; //multiplies real parts
    im=(x2*y1-x1*y2)/n; //multiplies imaginary parts
    return *this;
  }
  const scalar operator+(const scalar& b) //addition operator overload
  {
    scalar c = *this;
    c+=b;
    return c;
  }
  const scalar operator*(const scalar& b) //addition operator overload
  {
    scalar c = *this;
    c*=b;
    return c;
  }
  const scalar operator-(const scalar& b) //addition operator overload
  {
    scalar c = *this;
    c-=b;
    return c;
  }
  const scalar operator/(const scalar& b) //addition operator overload
  {
    scalar c = *this;
    c/=b;
    return c;
  }
};

scalar i(0.0,1.0);
scalar j(0.0,1.0);

std::ostream& operator<<(std::ostream& out, const scalar& s)
{
  out << s.re << '+' << s.im << 'i';
  return out;
}

scalar operator^(scalar a, int b) //integer power operator overload
{
  double x=a.real(); double y=a.imag();
  if (x==0) throw(1);
  int r=sqrt(pow(x,2)+pow(y,2));
  int arg=atan2(y,x);
  scalar c(r*cos(arg),r*sin(arg));
  return c;
}

scalar exp(const scalar& s) //exponential power function
{
  double x=s.re; double y=s.im;
  scalar c(exp(x)*cos(y),exp(x)*sin(y));
  return c;
}

这是我的主要功能:

int main()
{
  scalar x(3,4);
  scalar y=2;
  cout << x*y << endl;
  return 0;
}

这是它应该给出的输出:

6+8i

这是它给出的错误:

In function 'std::ostream& operator<<(std::ostream&, const scalar&)':|
error: passing 'const scalar' as 'this' argument of 'double scalar::real()' 
discards qualifiers|

如果我按照编译器的说法删除const,我会收到以下错误:

error: no match for 'operator<<' in 'std::cout << scalar::operator*(const scalar&)
(((const scalar&)((const scalar*)(& y))))'|

【问题讨论】:

  • 你必须为你的结构创建一个重载的
  • 您的代码有编译问题。你也可以去掉不需要的部分(^ 运算符,...)
  • ^ 重载为“幂”是个坏主意,因为它没有数学家所期望的优先级。
  • 请查看我的更新答案以修复上述代码 - 但我无法相信您显示的是产生上述错误的代码(您没有在 operator&lt;&lt; 的任何地方使用 real() !
  • @nyarlathotep 抱歉,我正在处理的项目包含许多源代码,我想我有点困惑,但我按照你说的做了,错误消失了。非常感谢。

标签: c++ operator-overloading ostream


【解决方案1】:

&lt;&lt; 运算符无法处理完整的表达式 - 为什么要处理?

您需要为您的结构实现单独的运算符(operator+、operator*、...),它们将您的结构作为参数,对其执行相应的操作,并返回另一个结构。并且只有 然后 定义一个 operator&lt;&lt; 来获取你的一个结构。

你怎么会想到将如此复杂的结构传递给运算符

例如对于仅封装int 的简单结构,使用+ 操作将如下所示:

struct mystruct
{
     int value;
};

然后定义:

mystruct const operator+(mystruct const & a, mystruct const & b)
{
    mystruct result;
    result.value = a.value + b.value;
    return result;
}

std::ostream & operator<<(std::ostream& out, mystruct const & a)
{
    out << a.value;
    return out;
}

那么你可以这样做:

mystruct a, b;
a.value = 1;
b.value = 2;
std::cout << a+b;

编辑:使用更新后的代码,确实存在一个问题:

std::ostream& operator<<(std::ostream&, const scalar&)

应该是

friend std::ostream& operator<<(std::ostream&, const scalar&);

即你错过了friend;

尽管您显示的错误表明了一些不同的问题(jrok 的答案将有一个解决方案) - 这似乎不是编译您显示的代码的结果!因此,请同步获取显示的代码和错误消息。

【讨论】:

  • 我确实重载了所有算术运算符和 ostream 运算符,它们分别工作,但是当我尝试将我的 ostream 用于此类表达式时,它给了我一个错误。
  • 当然可以重载 +, / 等,以便它们只存储调用它们的参数。然后让一个重载的
  • @MohammadSanei:那么一个或多个或那些重载有问题。或许你可以让我们看看?
  • @MohammadSanei:唯一的问题是你离开了friendoperator&lt;&lt; 的类内声明。如果我添加它,您的代码会给出预期的结果。或者,删除类内声明并使用公共接口实现operator&lt;&lt;,使real()imag() const
【解决方案2】:

只要你的重载运算符按值接受它的参数:

ostream& operator<<(ostream&, Thing)

或常量引用:

ostream& operator<<(ostream&, const Thing&)

您可以将其用于Thing 类型的任何表达式。

你应该在复杂的表达式周围加上括号,以避免运算符优先级的意外;特别是,涉及^ 的第二个表达式将不会按照您的预期进行解析。

如果运算符需要非常量引用,您将只能使用单个变量(或者更准确地说,lvalue 表达式);所以不要那样做。

更新 现在我们已经看到了代码,主要问题是operator&lt;&lt; 的类内定义为成员函数;它不能成为会员。也许您希望它是friend,因此它可以访问imre;或者也许您应该删除声明(使其成为非成员、非朋友),并只使用公共接口。如果这样做,则需要将const 添加到real()imag(),以便可以在const 对象上调用它们。无论如何你都应该这样做。

(看报错,好像你已经改成使用公共接口了,但是没有声明必要的函数const)。

【讨论】:

    【解决方案3】:

    你为什么不写std::cout &lt;&lt; (x+y) &lt;&lt; std::endl;
    完成了吗?

    【讨论】:

      【解决方案4】:

      错误是因为函数 scalar::realscalar::imag 不是 const - 只有在引用常量 scalar 时才能调用 const 成员函数。

         double real() const {return re;}
         double imag() const {return im;}
      

      【讨论】:

      • 这可能会修复错误消息,是的,但是显示的 operator
      • @nyarlathotep 确实如此,在operator^
      • 是的,但没有使用 - 并且显示的编译错误明确指出在运算符中出现 real()
      猜你喜欢
      • 2018-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多