C++ – Friending cin and overloading operator >>

c

Okay, hello. I am trying to compare two objects of Coordinate type (x, y, z) and my code compiles with no errors, but the output isn't quite correct. It looks like, to me, that my input isn't getting saved but I can't figure out why. I only included the relavant definitions.

Header file:

#ifndef COORDINATE_H  //if not defined
#define COORDINATE_H //Define

#include <iostream>
using namespace std;

    class Coordinate
    {
          friend istream& operator>>(istream &, Coordinate &);
          friend ostream& operator<<(ostream &, const Coordinate &);
    public:
            Coordinate(double = 0.0, double = 0.0, double = 0.0); //my default constructor
            Coordinate operator+(const Coordinate &);
            Coordinate operator-(const Coordinate &);
            Coordinate operator*(const Coordinate &);
            Coordinate& operator=(const Coordinate &);
            bool operator==(const Coordinate &);
            bool operator!=(const Coordinate &);
            void setCoordinate(double a, double b, double c);
    private:
            double x;
            double y;
            double z;
    };

    #endif //end definition.

Defintions:

    #include <iomanip>
    #include "Coordinate.h" //including the Coordinate header file
    using namespace std;

    bool Coordinate::operator==(const Coordinate & d)
    {
        return (this->x == d.x && this->y == d.y && this->z == d.z);
    }

    bool Coordinate::operator!=(const Coordinate & d)
    {
        return !(this->x == d.x && this->y == d.y && this->z == d.z);
    }

    Coordinate& Coordinate::operator=(const Coordinate & d)
    {
        if(this != &d)
        {
            x = d.x;
            y = d.y;
            z = d.z;
        }
        return *this;
    }


    ostream &operator<<(ostream & out, const Coordinate & d)
    {
        out << "(" <<d.x << "," << d.y << "," << d.z << ")" << endl;

        return out;
    }

    istream &operator>>(istream & in, Coordinate & g)
            {
        in >> g.x >> g.y >> g.z;
        return in;
    }

Best Answer

If you expect to read in the same format you write, you need to account for it explicitly.

You can do it with standard C++ streams:

istream& operator>>(istream& in, Coordinate& g) {
    char c;
    in >> c;        if (c != '(') { ... }
    in >> g.x >> c; if (c != ',') { ... }
    in >> g.y >> c; if (c != ',') { ... }
    in >> g.z >> c; if (c != ')') { ... }
    return in;
}

Unfortunately, this kind of solution doesn’t correctly backtrack or anything for invalid input. Of course, you could just set the fail bit and move on. To check literals automatically, you could add an overload for istream& and use std::ws to explicitly discard whitespace:

istream& operator>>(istream& in, char c) {
    in >> ws;
    if (in.peek() == c)
        in.ignore();
    else
        in.clear(ios::failbit);
    return in;
}

istream& operator>>(istream& in, Coordinate& g) {
    return in >> '(' >> g.x >> ',' >> g.y >> ',' >> g.z >> ')';
}

If you need something more involved than this, I imagine it will rapidly become unwieldy. You’ll basically end up parsing the input manually, character by character. At that point you should just use a proper parsing library to save yourself the trouble.