views:

193

answers:

1

I'm trying to write an overloaded stream insertion operator for a class who's only member is a vector. It's a vector of Points, which is a struct containing two doubles. I figure what I want is to insert user input (a bunch of doubles) into a stream that I then send to a modifier method. I'm working off other stream insertion examples such as:

std::ostream& operator<< (std::ostream& o, Fred const& fred)
 {
   return o << fred.i_;
 }

but when I try something similar:

 istream & operator >> (istream &inStream, Polygon &vertStr)
     {
        inStream >> ws;
        inStream >> vertStr.vertices;
        return inStream;
     }

I get an error "no match for operator >> etc etc." If I leave off the .vertices, it compiles, but I figure that's not right. (By the way, vertices is the name of my vector <Point>.) And even if it is right, I don't actually know what syntax to use in my program to use it, and I'm also not 100% sure on what my modifier method needs to look like.

Here's my Polygon class:

//header

#ifndef POLYGON_H
#define POLYGON_H
#include "Segment.h"
#include <vector>
class Polygon
{
 friend std::istream & operator >> (std::istream &inStream, Polygon &vertStr);
 public:
   //Constructor
    Polygon(const Point &theVerts);
    //Default Constructor
    Polygon();
    //Copy Constructor
    Polygon(const Polygon &polyCopy);
    //Accessor/Modifier methods
    inline std::vector<Point> getVector() const {return vertices;}
    //Return number of Vector elements
    inline int sizeOfVect() const {return (int) vertices.capacity();}
    //add Point elements to vector
    inline void setVertices(const Point &theVerts){vertices.push_back (theVerts);}

 private:
   std::vector<Point> vertices;
};
#endif

//Body

using namespace std;
 #include "Polygon.h"
// Constructor
Polygon::Polygon(const Point &theVerts)
    {
        vertices.push_back (theVerts);
        }
//Copy Constructor
Polygon::Polygon(const Polygon &polyCopy)
{
    vertices = polyCopy.vertices;
}
//Default Constructor
Polygon::Polygon(){}

istream & operator >> (istream &inStream, Polygon &vertStr)
 {
    inStream >> ws;
    inStream >> vertStr;
    return inStream;
 }

Sorry to be so vague; a lecturer has just kind of given us a brief example of stream insertion and then left us on our own.

+1  A: 

The problem is there is no standard extraction operator for vectors (insertion is to a stream, extraction from a stream), so you'll need to define your own. Also, streams skip whitespace by default, so you don't generally need to use std::ws. You didn't define how vector input is terminated, so I'm assuming a newline indicates the end of a vector.

Since this is a school problem, I can't give you too much. To start, here are some declarations for you to fill out, and some includes that might prove useful. It's bad form to import namespace std, so the following doesn't.

#include <list>

// returns true if ch is a horizontal space. Locales are a little tricky,
// so you could skip them for now and instead start with the functions defined 
// in header <ctype>
bool ishs(char ch, std::locale loc=std::locale::global());
// return true if ch is a vertical space
bool isvs(char ch);
// return true if the next character in stream 'in' is a vertical space.
bool eol(std::istream& in);

// reads & discards horizontal spaces
std::istream& hs(std::istream& in);

class Point {
public:
  // Scalar is so you can use 'Point::Scalar' rather than 'double', 
  // making it easy should you which to change the type that a Point holds.
  // When you've covered templates, this will make it trivial to templatize Point.
  typedef double Scalar;
  ...
};

class Polygon {
public:
     // adds pt as the last of this polygon's vertices
     // Note: this is basically your "setVertices" with a different name
   Polygon& append(const Point& pt);
     // adds the points from 'start' to 'end' to this polygon
   template <typename _Iter>
   Polygon& append(_Iter start, _Iter end);
     // remove all points in this polygon
   void erase();
     // returns the number of sides on this polygon, 
     // which is also the number of vertices
     // Note: this is different from your "sizeOfVect"; see below for more
   int sides() const { return vertices.size(); }
     // set aside space for polygon to have 's' sides.
   voids sides(int s) { vertices.resize(s); }
}

/* reads the next two numbers on the current line into pt.
   Throws an exception if there is only one number.
 */
std::istream& operator>>(std::istream& in, Point& pt);
/* reads numbers on the current line into points on 'poly'.
   Throws an exception if there is only one number. Preferably,
   won't alter 'poly' if there are an odd amount of numbers.

   you could also put the contents of this operator into >>(istream&, Polygon&)
 */
std::istream& operator>>(std::istream& in, std::vector<Point>& vertices) {
    std::list<Point::Scalar> points;
    Point pt;
    // while not at eol(in), read into pt and add it to points
    // After that, empty vertices, then add the Points in points to vertices
    ...
}

As an alternative to the character related functions (ishs, isvs, hs, eol), you can read the next line into a string with getline, thence into an istringstream and read points from that. The vector ends when the istringstream reaches eof (or strin >> pt is false).

What you need to do is turn the tasks in operator>>(istream&, vector<Point>&) into method and function calls, then:

  1. Declare the new methods and functions.
  2. Write a description of the tasks (as is done in the >> comment).
  3. Turn the description into method and function calls.
  4. Repeat until there are no more new methods or functions to write.

Why my Polygon::sides() is different from your Polygon::sizeOfVect(): note that vector::capacity returns the number of elements a vector can hold without resizing; that is, it's basically sizeof(vect)/typeof(element). vector::size is the number of elements currently stored in a vector. The two might differ if you preallocate space for elements, such as Polygon::sides(int) does, or if you pop elements off the back. No matter what, however, vector::capacityvector::size.

outis
ok, thanks for all that, i just need to go though and understand it now.
Julz