views:

294

answers:

5

hi, i'm trying to simply cout the elements of a vector using an overloaded extraction operator. the vector contians Point, which is just a struct containing two doubles. the vector is a private member of a class called Polygon, so heres my Point.h

#ifndef POINT_H
#define POINT_H
#include <iostream>
#include <string>
#include <sstream>
struct Point
{
  double x;
  double y;
  //constructor
  Point()
  {
   x = 0.0;
   y = 0.0;
  }

friend std::istream& operator >>(std::istream& stream, Point &p)
    {
    stream >> std::ws;
    stream >> p.x;
    stream >> p.y;
    return stream;
    }
friend std::ostream& operator << (std::ostream& stream, Point &p)
{
stream << p.x <<  p.y;
return stream;
}    
};
#endif

my Polygon.h

#ifndef POLYGON_H
#define POLYGON_H
#include "Segment.h"
#include <vector>
class Polygon
{
    //insertion operator needs work
 friend std::istream & operator >> (std::istream &inStream, Polygon &vertStr);
 // extraction operator
 friend std::ostream & operator << (std::ostream &outStream, const Polygon &vertStr);

   public:
   //Constructor
    Polygon(const std::vector<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 vertices.size();}
    //add Point elements to vector
    inline void setVertices(const Point &theVerts){vertices.push_back (theVerts);}

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

and Polygon.cc

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

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

// extraction operator
 ostream & operator << (ostream &outStream, const Polygon::Polygon &vertStr)
{
    outStream << vertStr.vertices << endl;
    return outStream;
 }

i figure my Point insertion/extraction is right, i can insert and cout using it

and i figure i should be able to just......

cout << myPoly[i] << endl;  

in my driver? (in a loop) or even...

cout << myPoly[0] << endl; 

without a loop? i've tried all sorts of

myPoly.at[i];
myPoly.vertices[i];

etc etc

also tried all veriations in my extraction function

outStream << vertStr.vertices[i] << endl;

within loops, etc etc.

when i just create a...

vector<Point> myVect;

in my driver i can just...

cout << myVect.at(i) << endl;

no problems.

tried to find an answer for days, really lost and not through lack of trying!!!

thanks in advance for any help. please excuse my lack of comments and formatting also there's bits and pieces missing but i really just need an answer to this problem

thanks again

+3  A: 

Look at this answer to this question.

The general idea here is, that you do indeed have to loop over your vector in order to print all contained objects, but you can to std::copy to do that for you. As target for the copy you simply use an std::ostream_iterator< Point >( std::cout ) (look here for documentation). The ostream_iterator then uses your overloaded operator << for Point to print the individual points. This would look thus:

std::copy( vertices.begin(), vertices.end(), std::ostream_iterator< Point >( std::cout ) );
Space_C0wb0y
Good answer, but you might want to explain why you should do it that way, and what it is doing. +1
rmeador
+1, though a little quote would help :)
Matthieu M.
Ok, ok, I added some explanation :)
Space_C0wb0y
ok, i got the loop working like this.....ostream i < vertStr.sizeOfVect(); i++) { outStream << vertStr.vertices.at(i) << endl; } return outStream; }i'm sure i tried that over and over, dont know what i did differently, but hey it works, thanks heaps everyone.
Julz
+1  A: 

Your input and output code shouldn't be member functions. Move the parts with istream and ostream outside the class body:

struct Point
{
   Point() : x(0.0), y(0.0) { }
   double x;
   double y;
};

inline std::istream& operator>> (std::istream& stream, Point& p)
{
    stream >> std::ws;
    stream >> p.x;
    stream >> p.y;
    return stream;
}

inline std::ostream& operator<< (std::ostream& stream, const Point& p)
{
  stream << p.x <<  p.y;
  return stream;
}

Since your struct has only public members, there's no need for friends. Also, when you write an output function, you ought to pass the object as a const reference.

Seth Johnson
good stylistic advice, but does not address the OP's question at all.
rmeador
It addresses the question of why `cout << vertices[i];` doesn't print.
Seth Johnson
Not really. They're not currently member functions. The `friend` makes them global functions, even when they're implementation happens to be inside the class definition.
Jerry Coffin
+1 - This advice, when followed, tends to eliminate many of the problems the OP is seeing, IME. This is the preferred way to write operator<<() and operator>>(); there is a long technical reason for this that I can't remember the name of....
sheepsimulator
as soon as i remove the friend i get errors that function can only have one argument?i tried pulling the functions out of the struct body but more errors, i tried creating a Point.cc and putting the functions bodies in there, nothing compiles?
Julz
If you remove `friend`, they definitely need to be outside the struct body. If you're including the header in multiple compilation units (.cc files) you have to either inline the functions (reflected in my edited post) or leave the declarations here and put the definitions (with relevant includes) in a separate file.
Seth Johnson
ah, i dont think i tried to inline them out of the body.thanks i'll try it.yeah, i did the .cc correctly, well what i figure was correct.
Julz
ok, got it going.thanks for that, i'm obviously new to c++ and have only done a limited amount of c so i appreciate the advice
Julz
+4  A: 

Taking things in order. First, terminology: operator<< is an insertion operator -- it inserts items into a stream. operator>> is an extraction operator -- it extracts items from the stream.

Second, you have some fairly serious problems in your insertion operators. Let's start at the bottom, point::operator<<. Right now you have:

friend std::ostream& operator << (std::ostream& stream, Point &p)
{
    stream << p.x <<  p.y;
    return stream;
} 

Now, let's consider what happens when we feed some real numbers to this, let's say 1.23 and 4.56. It'll write out:

1.234.56

This is clearly a problem. There's no way, from looking at the data itself, to figure out where the 'x' ends and the 'y' starts. We need to format the data so we can distinguish those:

std::ostream &operator<<(std::ostream &stream, Point const &p) { 
    return stream << p.x << " " << p.y;
}

Also note that since we're not going to modify the Point that's passed, I've changed it to a const reference.

When/if you try to store more than a single polygon in a file, you run into the same problem again -- you have a stream of vertices, but nothing to show which vertices belong to which polygons. For example, a square followed by a triangle might look like this:

0 0
1 0
1 1
0 1
1 1
2 2
0 2

One obvious way to deal with that would be to prefix each polygon with the number of vertices it contains, so the same data would look something like this:

4
0 0
1 0
1 1 
0 1
3
1 1
2 2 
0 2

Then we can re-generate the original polygons as we read them back in. To do that, we (obviously) need to write our operators appropriately:

std::ostream &operator<<(std::ostream &os, Polygon const &p) {
    std::vector<Point> v = p.getVector();
    os << v.size << "\n";

    // write each point out using operator<< for Point:
    std::copy(v.begin(), v.end(), std::ostream_iterator<Point>(os, "\n"));
    return os;
}

std::istream &operator>>(std::istream &is, Polygon &p) {     
    size_t size;
    is >> size;
    Point temp;
    for (int i=0; i<size; i++) {
        is >> temp;
        p.setVertices(temp);
    }
    return is;
}

Looking at how long this is getting, I think I'll stop there for now.

Jerry Coffin
yeah, i had formatting on the Point extraction but i thought i'd better remove it incase it was causing problems.i can sort of see what ur code's doing but i get errors that ostream_iterator is not a member of std?but befor that i get error no match for operator<< in os << std::vector.......from this line...os << v.size << "\n"; ??
Julz
@Julz:You need to `#include <iterator>`. The `v.size` should really be `v.size()` (one of the problems with typing code into an answer is that it will often contain minor errors like that).
Jerry Coffin
ah, thank you.its really hard to debug stuff that ur unfamiliar with.that's why all i really wanted was a simple answer along the lines of what i was doing. as in the loop i ended up sorting ouy.thanks heaps though.
Julz
A: 

To support this...

cout << myPoly[i] << endl;  

...you could give your Polygon class a public operator[] that simply calls the operator[] of its vertices member.

Point const& Polygon::operator[](size_t n) const 
{
   return vertices[n];
}  

If you choose to support writing as well as reading in this fashion, you'd create a non-const overload that returns a non-const reference, but otherwise looks the same. It might be a good idea to add some kind of error or invariant checking into that version, obviously.

janks
+1  A: 

ok, i got the loop working like this.....

ostream & operator << (ostream &outStream, const Polygon::Polygon &vertStr) 
{ 
for (int i = 0; i < vertStr.sizeOfVect(); i++) 
{ 
outStream << vertStr.vertices.at(i) << endl; 
} 
return outStream; 
} 

then just

cout << mainPoly << endl;

in the driver

i'm sure i tried that over and over, dont know what i did differently, but hey it works thanks heaps everyone.

Julz