how to cout a vector of structs (that's a class member, using extraction operator)
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 开发者_JAVA技巧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!
please excuse my lack of comments and formatting also there's bits and pieces missing.
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.
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 ) );
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.
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.
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.
精彩评论