Home > Blockchain >  How do I overload a stream operator properly?
How do I overload a stream operator properly?

Time:10-20

I am trying to overload the >> operator so that I can take an open ifstream file and read its contents into an array in my class. For some reason when I do something like this

ifstream puzzle;
Sudoku x; //Sudoku is the name of myclass
puzzle.open("example.txt", ios::in);
puzzle >> x;    

it doesn't transfer what I want over to my x object. No errors pop up after running my code but when I look at what is in the array for my object it just has an array full of zeros, as it is initialized. This is a basic recreation of my code.

class Sudoku
{
public:
    Sudoku();
    ~Sudoku(){}
    int getValue(int row, int col){return grid[row][col];}
    void setValue(int row,int col,int num) {grid[row][col]=num;}
    friend ifstream& operator>>(ifstream &input, Sudoku &s);
private:
    int grid[9][9];
};


 ifstream& operator>>(ifstream &input, Sudoku &s)
 {
     int x = 0, i = 0, j = 0;

     while (input >> x)
     {
         if (j >= 9)
         {
             i  ;
             j = 0;
         }
         if (i >= 9)
         {
             return input;
         }

         s.setValue(i, j, x);

         j  ;
     }
      return input;
}

CodePudding user response:

Your function populates x just fine if the input file is properly formatted - but there's one big flaw. You read, while (input >> x), before checking if you should read. If you've already read all values in the file at that point, it'll set the failbit on the input stream, so if you do this to check:

if(puzzle >> x) {
    std::cout << "success\n";
} else {
    std::cout << "failure\n";
}

It will print, "failure`, even though all values were read - just because you tried to read one value too much.

I suggest simplifying it to only read exactly as many values as there are (9 x 9), and also, make it read from any istream, not only ifstreams.

The friend declaration becomes:

friend std::istream& operator>>(std::istream &input, Sudoku &s);

And the implementation:

std::istream& operator>>(std::istream &input, Sudoku &s) {
    for(int i = 0; i < 9;   i) {
        for(int j = 0; j < 9;   j) {
            // There's no need to use setValue since you made it a friend
            input >> s.grid[i][j];
        }
    }
    return input;
}

Inspect your input file. Does it have whitespaces between the numbers? If it doesn't - make sure it does or else your operator>> will not work.

CodePudding user response:

Below is a complete, working example. You'll notice a few things.

  1. I never use friend classes, and there was no reason to do so.
  2. I made an operator>> function so I could write it back out.
  3. My operator<< expects an istream rather than the more specific ifstream. The method shouldn't care that it's an ifstream, so making it more generic is better.
  4. And mine is simpler than yours.

It compiles (at least under C 17) and runs properly. I'm not entirely sure why yours doesn't work.

#include <iostream>
#include <fstream>

using std::cout;
using std::endl;
using std::ifstream;
using std::istream;

class Sudoku
{
public:
    Sudoku() {};
    ~Sudoku(){}
    int getValue(int row, int col){return grid[row][col];}
    void setValue(int row,int col,int num) {grid[row][col]=num;}

private:
    int grid[9][9];
};

std::istream & operator>> (std::istream &input, Sudoku &s)
{
    int row = 0;
    int col = 0;
    while (row < 9) {
        int cellValue;
        if (!(input >> cellValue)) {
            std::cout << "Out of input." << endl;
            return input;
        }
        s.setValue(row, col, cellValue);
        if (  col >= 9) {
              row;
            col = 0;
        }
    }
    return input;
}

std::ostream & operator<< (std::ostream &oStr, Sudoku &s) {
    for (int row = 0; row < 9;   row) {
        for (int col = 0; col < 9;   col) {
            if (col % 3 == 0) {
                oStr << " ";
            }
            oStr << s.getValue(row, col);
        }
        oStr << endl;
    }
    return oStr;
}

int main(int, char **) {
    std::ifstream input("sudoku.txt");
    Sudoku sudoku;

    input >> sudoku;
    std::cout << sudoku << std::endl;
}
  •  Tags:  
  • c
  • Related