简体   繁体   中英

Is it possible to overload the ostream operator for arithmetic expressions?

Is it possible to create an overload for the ostream operator that does an arithmetic operation (addition for example) and then streams out the result? The standard ostream overload that can be found all over the web can only stream from a single variable. I need something that does the following:

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

or even more complex expressions like:

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

where x, y, and z are instances of a simple custom-made struct where arithmetic operations are already defined (overloaded).

EDIT:

Here is my code:

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;
}

Here is my main function:

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

This is is the output it is supposed to give:

6+8i

And this is the errors it gives instead:

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

And if I remove the const as the compiler says, I will get the following error:

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

The << operator can't handle the full expression - and why should it?

You need to implement the separate operators (operator+, operator*, ...) for your struct, which take your structs as parameters, do the corresponding operation on it, and return another of your structs. And only then define a operator<< taking a single one of your structs.

How would you even think of passing in such a complex structure to the operator<<, let alone parse it in there? Implement the separate operators, and leave the parsing to the compiler.

eg for a simple struct only encapsulating an int , doing that with + operation would look like this:

struct mystruct
{
     int value;
};

then define:

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

and

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

then you can do:

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

Edit: With your updated code, there's exactly one problem:

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

should be

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

ie you're missing friend and an ;

Though the error you show suggests some different problem (which jrok 's answer would have a solution for) - that doesn't seem to result from compiling the code you show! So please get the shown code and error message in sync.

Why don't you just write std::cout << (x+y) << std::endl;
and be done?

The error is because functions scalar::real and scalar::imag are not const - you can only call const member functions when you've got a reference to a constant scalar .

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

As long as your overloaded operator takes its argument by value:

ostream& operator<<(ostream&, Thing)

or constant reference:

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

you can use it for any expression with type Thing .

You should put parentheses around complex expressions, to avoid surprises from operator precedence; in particular, the second expression involving ^ won't be parsed as you expect.

You'll only be restricted to a single variable (or, more accurately, an lvalue expression) if the operator requires a non-constant reference; so don't do that.

UPDATE Now we've seen the code, the main issue is the in-class definition of operator<< as a member function; it can't be a member. Perhaps you want it to be a friend , so it can access im and re ; or perhaps you should remove the declaration (making it a non-member, non-friend), and just use the public interface. If you do that, you'll need to add const to real() and imag() , so they can be called on a const object. You should do that anyway.

(Looking at the reported error, it seems you've already changed it to use the public interface, but haven't declared the necessary functions const ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM