I use two Points to define a Line and also a LineSegment, like:
class Point { ... };
class Line
{
Point p1, p2;
//...
};
class LineSegment
{
Point p1, p2;
//...
};
LineSegment has the same definition as Line, so I used typedef Line LineSegment at first instead of defining another LineSegment class. But soon, I found I couldn't define the function distance to calculate the distance between a point and a line or a point and a line segment.
class Point { ... };
class Line
{
Point p1, p2;
//...
};
typedef Line LineSegment;
double distance(const Point& a, const Line& b) { ... }
double distance(const Point& a, const LineSegment& b) { ... }
Certainly I will get a compile error.
So, my question is: Is there a better way to distinguish Line from LineSegment without redefine LineSegment?
I follow #Amadan's suggestion. Create a abstract class.
#include <iostream>
struct Point { int x, y; };
struct AbstractLine { Point p1, p2; };
struct Line : AbstractLine { };
struct LineSegment : AbstractLine { };
void distance(const Point& a, const Line& b)
{
std::cout << "void distance(const Point& a, const Line& b)" << std::endl;
}
void distance(const Point& a, const LineSegment& b)
{
std::cout << "void distance(const Point& a, const LineSegment& b)" << std::endl;
}
int main()
{
Point p;
Line a;
LineSegment b;
distance(p, a);
distance(p, b);
}
A line segment has a start point and an end point, whereas a line may be uniquely defined by only the point on it closest to the origin (or some other representation).
So the Line representation is either invalid or excessive.
Edit: Aha, I knew I was missing something! If you use the point on the line closest to the origin (x, y), then the slope is (–x/y), and a second point on the line can easily be constructed at (x+y, y–x). So the implementation of Line can compute that to delegate operations to LineSegment using a temporary object, at less expense than loading additional values from memory. (The temporary should live entirely in registers.)
class LineSegment {
std::array< Point, 2 > terminus;
public:
double angle() { return ... }
};
class Line {
Point nearest_origin;
LineSegment toLineSegment() {
return {
nearest_origin,
{ nearest_origin[0] + nearest_origin[1],
nearest_origin[1] - nearest_origin[0] }
};
}
public:
double angle()
{ return toLineSegment().angle(); }
};
(Ugh… now that I wrote all that I can see that actually you want delegation to go the other way here, and subtract the coordinates of LineSegment to produce a Line at the correct angle. Anyway, this works and you get the point. Such delegation can go both ways, whereas inheritance is usually a one-way street.)
Moreover, you shouldn't typedef things just because the data members inside are similar. Why not just typedef them both to arrays? A class represents a distinct concept.
I recommend against the AbstractLine suggestion, unless there are meaningful methods to put in there. Start from the interface and fill in the internal details in the most convenient way. Classes shouldn't share implementation just because they look the same, but because the implementations are doing conceptually the same thing.
Because math is tricky, math classes should be written to allow changing internal representations, and public inheritance is a bit dangerous. Because math doesn't involve "actors" and actions, but rather generic operations with properties like commutativity, OOP is often a poor fit in general.
Related
I have some C structs that I would like to 'extend' in C++ to add some convenience and type safety. For instance, suppose that my struct is
struct vector2D { float x, y; };
From a number of sources, I have gathered that the safest way to warp this struct in C++ is to subclass it:
struct Vector2D: vector2D { ... };
So far so good. However, what I am having difficulties figuring out how I can reinterpret the C struct as the extended version. Suppose I have a C function
struct vector2D do_some_stuff(struct vector2D _a, struct vector2D _b) {
...
}
Within this function, I would like to work with the C++ representation. Since the layouts of struct vector2D and Vector2D are identical, I though that simple cast would work, e.g.
Vector2D a = static_cast<Vector2D>(_a)
but this doesn't seem to work. Using a constructor generates horrible boilerplate code.
What is the proper way of doing this, if its at all possible?
Clarification: do_some_stuff is a C function and is only intended to be called from C code.
Prefer composition over inheritance. That is change your C++ class Vector2D to contain an instance of C struct vector2D and interface it:
class Vector2D {
vector2D p;
public:
vector2D& getP() { return p; }
vector2D const& getP() const { return p; }
float& x() { return p.x; }
float& y() { return p.y; }
float const& x() const { return p.x; }
float const& y() const { return p.y; }
// ...
};
And then call the C function as:
Vector2D v1;
Vector2D v2;
...
auto p = do_some_stuff(v1.getP(), v2.getP());
However, what I am having difficulties figuring out how I can reinterpret the C struct as the extended version.
Um, that's not how inheritance works: your daughter class is a specialization of your mother class, so you can interpret a Vector2D as a vector2d, but not the other way around.
Think about it: where should the extension's data come from if it wasn't there in the first place?
What you can do is implement a constructor or cast operator that takes a vector2d to initialize a new Vector2D.
Other than that, I'd say your whole endeavour is questionable, because it's based on a misunderstanding: The struct you're extending is a C++ class now, different from the C type.
After some experimentation, I have figured the way to do it:
Vector2D v = *reinterpret_cast<Vector2D*>(&_v);
But juanchopanza's suggestion to use non-member functions is probably the better way to go.
I would like to have an insight about whenever I should be using references or pointers.
Let's take the example of a Polygon class using a Rectangle class for its internal bounding box.
Polygon.h
class Polygon {
private:
std::list<Point> _points;
Rectangle _boundingBox;
public:
Polygon(const std::list<Point> &);
public:
const std::list<Point> &getPoints() const;
const Rectangle &getBoundingBox() const;
private:
void setBoundingBox();
};
Polygon.cpp
#include <iostream>
#include "Polygon.h"
Polygon::Polygon(const std::list<Point> &points)
{
if (points.size() < polygon::MIN_SIDE + 1) {
throw std::invalid_argument("A polygon is composed of at least 3 sides.");
}
if (points.front() != points.back()) {
throw std::invalid_argument("A polygon must be closed therefore the first point must be equal to the last one.");
}
std::list<Point>::const_iterator it;
for (it = ++points.begin(); it != points.end(); ++it) {
this->_points.push_back(*it);
}
this->setBoundingBox();
}
void Polygon::translate(const std::array<float, 2> &vector)
{
std::list<Point>::iterator it;
for (it = this->_points.begin(); it != this->_points.end(); ++it) {
(*it).setX((*it).getX() + vector[0]);
(*it).setY((*it).getY() + vector[1]);
}
Point topLeft = this->_boundingBox->getTopLeft();
Point bottomRight = this->_boundingBox->getBottomRight();
topLeft.setX(topLeft.getX() + vector[0]);
topLeft.setY(topLeft.getY() + vector[1]);
bottomRight.setX(bottomRight.getX() + vector[0]);
bottomRight.setY(bottomRight.getY() + vector[1]);
}
const std::list<Point> &Polygon::getPoints() const
{
return this->_points;
}
const Rectangle &Polygon::getBoundingBox() const
{
return this->_boundingBox;
}
void Polygon::setBoundingBox()
{
float xMin = this->_points.front().getX();
float xMax = this->_points.front().getX();
float yMin = this->_points.front().getY();
float yMax = this->_points.front().getY();
std::list<Point>::const_iterator it;
for (it = this->_points.begin(); it != this->_points.end(); ++it)
{
Point point = *it;
if (point.getX() < xMin) {
xMin = point.getX();
}
if (point.getX() > xMax) {
xMax = point.getX();
}
if (point.getY() < yMin) {
yMin = point.getY();
}
if (point.getY() > yMax) {
yMax = point.getY();
}
}
this->_boundingBox = new Rectangle(Point(xMin, yMin), Point(xMax, yMax));
}
std::ostream &operator<<(std::ostream &out, const Polygon &polygon)
{
std::list<Point>::const_iterator it;
for (it = polygon.getPoints().begin(); it != polygon.getPoints().end(); ++it) {
out << (*it);
if (it != polygon.getPoints().end()) {
out << " ";
}
}
return out;
}
Rectangle.h
#pragma once
#include <stdexcept>
#include "Point.h"
class Rectangle {
private:
Point _topLeft;
Point _bottomRight;
public:
Rectangle(const Point &, const Point &);
public:
const Point &getTopLeft() const;
const Point &getBottomRight() const;
float getWidth() const;
float getHeight() const;
};
Rectangle.cpp
#include "Rectangle.h"
Rectangle::Rectangle(const Point &topLeft, const Point &bottomRight)
{
if (topLeft.getX() > bottomRight.getX() || topLeft.getY() > bottomRight.getY()) {
throw std::invalid_argument("You must specify valid top-left/bottom-right points");
}
this->_topLeft = topLeft;
this->_bottomRight = bottomRight;
}
const Point &Rectangle::getTopLeft() const
{
return this->_topLeft;
}
const Point &Rectangle::getBottomRight() const
{
return this->_bottomRight;
}
float Rectangle::getWidth() const
{
return this->_bottomRight.getX() - this->_topLeft.getX();
}
float Rectangle::getHeight() const
{
return this->_bottomRight.getY() - this->_topLeft.getY();
}
Point.h
#pragma once
#include <ostream>
#include <cmath>
class Point {
private:
float _x;
float _y;
public:
Point(float = 0, float = 0);
public:
float distance(const Point &);
public:
float getX() const;
float getY() const;
void setX(float);
void setY(float);
};
std::ostream &operator<<(std::ostream &, const Point &);
bool operator==(const Point &, const Point &);
bool operator!=(const Point &, const Point &);
Point.cpp
#include "Point.h"
Point::Point(float x, float y)
{
this->_x = x;
this->_y = y;
}
float Point::distance(const Point &other)
{
return std::sqrt(std::pow(this->_x - other.getX(), 2) + std::pow(this->_y - other.getY(), 2));
}
float Point::getX() const
{
return this->_x;
}
float Point::getY() const
{
return this->_y;
}
void Point::setX(float x)
{
this->_x = x;
}
void Point::setY(float y)
{
this->_y = y;
}
std::ostream &operator<<(std::ostream &out, const Point &point)
{
out << "(" << point.getX() << ", " << point.getY() << ")";
return out;
}
bool operator==(const Point &p1, const Point &p2)
{
return p1.getX() == p2.getX() && p1.getY() == p2.getY();
}
bool operator!=(const Point &p1, const Point &p2)
{
return p1.getX() != p2.getX() || p1.getY() != p2.getY();
}
A lot of questions come with this snippet of code.
This does not compile because obviously whenever we try to create a Polygon, it ends up trying to create a Rectangle with a default constructor which does not exist.
I can't use initializer list because obviously the bounding box depends on some computed values from my list of points.
I could create a default constructor creating two Point(0, 0) by default for the Rectangle but this does not make much sense.
I could use pointers but then I feel this is not the nicest solution as I tend to think this is mostly used for polymorphism in C++ we should prefer reference whenever possible.
How should I then proceed ?
I feel I am missing something out about C++ and could learn a lot from this.
I think your main question is about how to deal with the problem of needing to initialize both std::list<Point> _points; and Rectangle _boundingBox;, while also doing some validation of _points.
The simplest solution is to just give Rectangle a default constructor (or pass two default Points as initializer). Then once you have validated the points argument in the constructor, you calculate the Rectangle based on the points.
A slightly more complicated alternative is to allow the validation function to be invoked from the ctor-initializer list, e.g.:
Polygon::Polygon(std::list<Point> points)
: _points( validate_point_list(points), std::move(points) ), _boundingBox( calculateBoundingBox(_points) )
{
}
where you have functions (which could be free functions):
void validate_point_list(std::list<Point> &points)
{
if (points.size() < polygon::MIN_SIDE + 1)
throw std::invalid_argument("A polygon is composed of at least 3 sides.");
if (points.front() != points.back())
throw std::invalid_argument("A polygon must be closed therefore the first point must be equal to the last one.");
// caller must pass in same first and last point, but we only store one of the two
points.erase( points.begin() );
}
and
Rectangle calculateBoundingBox(std::list<Point> const &_points)
{
// whatever logic you have in setBoundingBox, except return the answer
}
Note that the loop in your Polygon constructor is unnecessarily complicated. You could have just written _points = points; and then erased the extra point (which is O(1) for lists).
Note that I have passed by value and then used std::move. The reason is that if the argument given is a rvalue then it can just be moved right on through into where it's being stored; whereas with the const & version, a copy is stored and then the original is destructed.
I would use const & a lot less than you did. Small objects , such as Point and Rectangle, don't suffer a performance penalty from pass-by-value (and might even be more efficient that way). And as mentioned in the previous paragraph; if your function accepts a parameter and it is going to take a copy of that parameter, it's better to pass by value .
Passing by reference is best only when you are using but not storing the values passed. For example, calculateBoundingBox.
Finally, once you get this working, you might want to think about having the Polygon constructor accept an iterator pair of points range, and/or a std::initializer_list.
I would defined a default constructor for Rectangle class as private and I would make Polygon class a friend of Rectangle class:
class Rectangle {
friend class Polygon;
Point _topLeft;
Point _bottomRight;
Rectangle(); // accessible only to friends
public:
Rectangle(Point const&, Point const&);
...
};
And then in setBoundingBox():
void Polygon::setBoundingBox() {
...
_boundingBox._topLeft = Point(xMin, yMin);
_boundingBox._bottomRight = Point(xMax, yMax);
}
Thus, I wouldn't expose the default constructor of Rectangle and at the same time I would have a concrete object which is more efficient in terms of cache performance.
I feel as though you should have a separate class called BoundingBox that
1) Takes a collection of points in its constructor
2) Is inherited from Rectangle
Meanwhile, Rectangle should have a state, along the lines of NOT_A_RECTANGLE or it could throw an exception. Just be sure you clean up when throwing exceptions from a constructor.
Then you would construct the bounding box as part of the construction of the polygon and you can verify that a bounding box is possible as part of your error checking. (probably rather than 3 sides check, but I am no geometry expert)
BoundingBox would remain a member of Polygon.
This would be more RTTI.
It occurs to me though, that if you translate or rotate the polygon, you've also go to translate or rotate the bounding box. You might want to consider making the list of points its own object and sharing them. This would be a more advanced topic. You can for now get away with just recalculating the bounding box on operations performed upon the polygon.
As to whether to use a reference, a pointer, or pass by value, I don't know that there is a black and white list of things to consider for this, but a few are:
Is the object large enough to even worry about it? A rectangle is 4 floats?
Are there interfaces or base classes you will need to cast to, rather than always using the class itself? If so, you've got no choice but to use a pointer of some sort. The pointer could be unique, shared, weak, etc. depending on the situation. You have to ask yourself who owns it, whats the life time, and are there circular references?
Most people will probably use a reference whenever possible rather than a pointer, but only when passing by value doesn't qualify.
IMO, since you are just "GetBoundingBox", I think it would be simple and more maintainable to just return a copy of the bounding box by value rather than some const reference and definitely more than a pointer.
One solution would be to write a programmatic constructor for Rectangle that takes as its argument a const std::list<Point>&. It could traverse the list once, computing the maximum and minimum x and y. Then, your Polygon constructor would become:
Polygon::Polygon(const std::list<Point> &points)
: _points(points),
: _boundingBox(points)
{
// ...
}
An alternative is to move the code to find the bounding box from a list of points to a helper function, then define a move constructor Rectangle::Rectangle( Rectangle&& x ). In that case, your Polygon constructor would be:
Polygon::Polygon(const std::list<Point> &points)
: _points(points),
: _boundingBox( findBoundingBox(points) )
{
// ...
}
Either way, you could update a bounding box with assignment, so you might want an assignment operator like Rectangle& Rectangle::operator= ( Rectangle&& x ) to make that more efficient. You can skip the Rectangle&& versions if a Rectangle is just Plain Old Data. But if you do this a lot, you might overload Rectangle& findBoundingBox( const std::list<Point>& src, Rectangle& dest ) to update in place with no copying.
On a minor side note, I’d discourage you from using identifiers that begin with underscores, since those names are reserved in the global namespace in C++, and your libraries might declare something named _point.
This is a general question on programming style. Let's say I have an object Line which has some methods and private variables Point point_a_ and Point point_b_. Let's say that at some point I need to change the position of the two points. What programming style would you prefer between the following cases? They all do the same thing (or should do: I didn't compile, but seems pretty straightforward).
CASE 1
Class Line {
public:
Line(Point point_a, Point point_b) : point_a_(point_a), point_b_(point_b) {}
void UpdatePoints(Point point_a, Point point_b) {
point_a_ = point_a; point_b_ = point_b;
}
double Distance();
private:
Point point_a_;
Point point_b_;
};
int main (int argc, char * const argv[]) {
Point point_a(0,0,0);
Point point_b(1,1,1);
Line line(point_a,point_b);
std::cout<<line.Distance()<<"\n";
point_a.x = 1;
line.UpdatePoints(point_a,point_b);
std::cout<<line.Distance()<<"\n";
}
CASE 2
Class Line {
public:
Line(Point point_a, Point point_b) : point_a_(point_a), point_b_(point_b) {}
Point& point_a() { return point_a_; }
Point& point_b() { return point_b_; }
double Distance();
private:
Point point_a_;
Point point_b_;
};
int main (int argc, char * const argv[]) {
Point point_a(0,0,0);
Point point_b(1,1,1);
Line line(point_a,point_b);
std::cout<<line.Distance()<<"\n";
line.point_a().x = 1;
std::cout<<line.Distance()<<"\n";
}
CASE 3
Class Line {
public:
Line(Point* point_a, Point* point_b) : point_a_(point_a), point_b_(point_b) {}
double Distance();
private:
Point* point_a_;
Point* point_b_;
};
int main (int argc, char * const argv[]) {
Point point_a(0,0,0);
Point point_b(1,1,1);
Line line(&point_a,&point_b);
std::cout<<line.Distance()<<"\n";
point_a.x = 1;
std::cout<<line.Distance()<<"\n";
}
Any feedback is greatly appreciated!!
Thanks!
[EDIT] Speed is paramount in my software!
In this simple scenario I might just use public member variables.
Otherwise I would provide getters that return a const reference and matching setters.
class Line {
public:
Line(const Point& p1, const Point&p2) : m_p1(p1), m_p2(p2) {}
const Point& p1() const
{ return m_p1; }
const Point& p2() const
{ return m_p2; }
void setP1(const Point& p1)
{ m_p1 = p1; }
void setP2(const Point& p2)
{ m_p2 = p2; }
private:
Point m_p1;
Point m_p2;
};
Case three is totally out because it completely violates principles of encapsulation. Case two does as well, to a slightly lesser extent. I would prefer option one, but did you consider possibly making the points immutable and forcing you to create a new object when it changes?
Also to be pedantic if I remember correctly from many years ago, a line technically extends infinitely in both directions. You're actually representing a line segment.
Case 2 is no better than public member variables. In particular, it doesn't encapsulate anything.
Case 3 makes ownership of the points unclear. Consider what happens if your points are local variables in the calling function, and then they go out of scope. It also offers no benefits over public member variables.
So out of these three options, Case 1 is the cleanest, IMO. Other options are:
simply use public member variables.
make Line immutable.
use set and get functions.
I would choose either case 1 or an immutable Line class.
Case 2 allows changes to the Point objects without the knowledge of their containing line. At some point, you might need the line to know if its points have been changed.
Case 3 either makes the Line object dependent on the lifetime of the Points, or makes the Line the owner of the points, which is not clear from the API.
An immutable Line would allow you to create a new Line object with new points.
Case 4 -- Prefer passing by const reference rather than value (or pointer):
class Line
{
public:
Line(const Point& a, const Point& b) : a_(a), b_(b)
{}
const Point& get_a() const { return a_; }
const Point& get_b() const { return b_; }
void set_a(const Point& a) { a_ = a; }
void set_b(const Point& b) { b_ = b; }
private:
Point a_;
Point b_
};
This is better in that in enforces encapsulation - the only way to change the variables held in the class after construction is a specific mutator method.
The accessors return a const reference, so they cannot be modified (copies made from these can be).
The class as a whole is made const-correct.
References are arguably better than pointers in this instance because they are guaranteed (unless you specifically break that guarantee) to not be NULL.
Consider another option:
class Segment {
public:
Segment(Point point_a, Point point_b);
Point point_a() const;
Point point_b() const;
private:
Point point_a_;
Point point_b_;
};
double Distance( Segment seg );
int main (int argc, char * const argv[]) {
Point point_a(0, 0, 0);
Point point_b(1, 1 ,1);
Segment seg(point_a, point_b);
std::cout << Distance(seg) << "\n";
point_a.x = 1;
seg = Segment(point_a, point_b); // reset
std::cout << Distance(seg) << "\n";
}
I used the name Segment as per suggestion above. This style is closer to functional programming style. Segment is immutable unless you explicitly reset it with a common assignment syntax. Distance is not a member function because it can be implemented in terms of Segment's public interface.
Regards,
&rzej
Is it worth to write classes representing 1D, 2D, 3D points using templates
template <class T>
class Point2D
{
protected:
T X, Y;
public:
Point2D(const T x, const T y) : hot smileyx), Y(y)) {}
...
};
template <class T>
class Point3D : public Point2D<T>
{
protected:
T Z;
public:
Point3D(const T x, const T y, const T z) : Point2D<T>(x,y), Z(z) {}
...
};
...or using this approach:
class Point2D
{
protected:
double X, Y;
public:
Point2D(const double x, const double y) : X(x), Y(y)) {}
...
};
class Point3D : public Point2D
{
protected:
double Z;
public:
Point3D(const double x, const double y, const double z) : Point2D(x,y), Z(z) {}
...
};
We understand the coordinates as continuous variables, so it makes sense to express them using double values. A similar situation arises when working with matrices. However in this case templates are widely used...
This class is not only for single use, but it will be part of the library... And my second part of the question. How some "measure" functions should be implemented?
template <class T>
T getDist(const Point2D <T> * p1, const Point2D<T> *p2)
{
....
}
or
double getDist(const Point2D <T> * p1, const Point2D<T> *p2)
{
....
}
Is it reasonable to write such function in general or for some specific type?
Why repeat yourself? Most of the content of those classes and functions will be the same.
Something like this works much better:
template <std::size_T N, typename T>
class Point
{
public:
Point()
{
std::fill_n(mData, N, T());
}
explicit Point(const T& pX) :
mData[0](pX)
{
// or some variant (enable_if also works)
static_assert(N == 1, "X constructor only usable in 1D");
}
explicit Point(const T& pX, const T& pY) :
mData[0](pX),
mData[1](pY),
{
static_assert(N == 2, "XY constructor only usable in 2D");
}
// incomplete, left as exercise for reader. :P
private:
T mData[N];
};
And you just use loops for the functions:
template <std::size_T N, typename T>
T getDist(const Point<N, T>& pFirst, const Point<N, T>& pSecond)
{
// generic, compiler will unroll loops
}
Based on my experience, I'd avoid like the plague creating a class hierarchy where a 3D point IS-A 2D point. It makes it far too easy for 3D points to unintentionally and silently be treated as 2D points. Better to keep coordinates of different dimensionality distinct types (as per GMan's answer) and require explicit coercion between types.
My current favourite implementation of this sort of thing is provided by Eigen. Even if it's license (LGPL) limits it's use to you, I'd suggest taking a look at it's elegantly templated vector and matrix types and learning from them.
It looks OK to me, provided that all functions are implemented correctly and efficiently. For distance measurement:
template <class T>
T getDist(const Point3D <T>& p1, const Point3D<T>& p2);
signature should be used. Distances can be in 3D also.
I've run into this situation, and had cause to allow different types for the X and Y values, where X was sometimes integral but Y always had higher precision (float or double depending on usage). Might be worth considering that upfront.
Some consideration should also be made on how the class will be used. You mentioned matrices. If you plan on solving systems using that class or anything else incolving matrix inversions (or other similar matrix operations) representing a matrix as a bunch of integers would be outlandish.
If you plan to use it as simply a table of sorts (or are only going to be adding/subtracting and multiplying the matrices) then you could template the class because a matrix full of integers would not provide weird (and incorrect) results for those operations.
I want to sort points_vec vector as shown in the pseudocode below. I want to sort this vector, by a coordinate value like x or y or z
class A{
std:vector<double*> points_vec;
void doSomething();
}
Then, in method A::doSomething, I want sort this vector:
void A::doSomething() {
std::sort(points_vec.begin(), points_vec.end(), sortPoints());
}
Can someone please show me syntax for the sortPoints() method.. Preferably I want it to be a method of class A. this post creates a struct to do this, not sure if I should create a similar struct within the class. Is there another way to handle this?
thanks
The simplest way is to provide a functor which is used by the sort algorithm to compare two values. You can write like this:
struct Compare
{
bool operator()(double* first, double* second) const
{
//Compare points here
}
};
And use like:
std::sort(p.begin(), p.end(), Compare());
EDIT for comment by OP: Yes, this sample code compiles fine:
class A
{
public:
struct c
{
bool operator()(int a, int b) const
{
return a < b;
}
};
};
int main()
{
std::vector<int> a1;
a1.push_back(2);
a1.push_back(1);
std::sort(a1.begin(), a1.end(), A::c());
return 0;
}
You have two options for sorting: either pass a function/functor to sort or define the operator< for your class. Now, your class A seems to be more of a wrapper for a set of coordinates. So, create another class for your co-ordinates.
struct Point {
double x_, y_, z_;
Point(double x, double y, double z) : x_(x), y_(y), z_(z) {}
// just an example, you can refine the following as much as you need
bool operator<(Point const& other) {
return x < other.x;
}
};
bool sortOnY(Point const& l, Point const& r) const {
return l.y < r.y;
}
class A {
std::vector<Point> pts_;
void doSomething() {
sort(pts_.begin(), pts_.end());
}
// if sorting on y is also required, you will need
// to use a custom comparator which can be either
// a functor or a function
void doSomeOtherThing() {
sort(pts_.begin(), pts_.end(), sortOnY);
}
};
First of all - what you have will break all your points - as you'll sort by single doubles not by "points consisting of 3 doubles".
The best way to do this I think is:
Store the points as some Point3D class not a couple doubles
Define the less then operator for Point3D
Just call std::sort(points_vec.begin(), points_vec.end() );
If you'd want to sort them by in different ways that's when you'd use the sort functor and create different functors with operators() for different purposes.
I don't think this thread would be complete without a mention of Boost.Bind:
struct Point3D {
double x, y;
Point3D(double x=0., double y=0.) : x(x), y(y) {
}
};
int main() {
std::vector<Point3D> points;
points.push_back(Point3D(-1., 2.));
points.push_back(Point3D( 2., -1.));
points.push_back(Point3D(-2., 0.));
using boost::bind;
std::sort(points.begin(), points.end(),
bind(&Point3D::x, _1) < bind(&Point3D::x, _2));
// points sorted by x coord
std::sort(points.begin(), points.end(),
bind(&Point3D::y, _1) < bind(&Point3D::y, _2));
// points sorted by y coord
}
What a shame std::tr1::bind does not support that. But of course, with a C++0x compiler you'll be able to do this:
std::sort(points.begin(), points.end(),
[](Point3D const & a, Point3D const & b) { return a.x < b.x; });
If you want to sort by x or y or z, those are three different functionalities. Which coordinate to sort by is extra information which doesn't really come from std::sort. You need have an object to pass it on.
struct coord_comparison {
int coord_id; // <= critical information
bool operator()( double (*l)[3], double (*r)[3] ) {
return (*l)[ coord_id ] < (*r)[ coord_id ];
}
coord_comparison( int id ) { coord_id = id; }
};
Create this struct inside your class or outside, but it needs to be a structure and not a free function, and operator() cannot be static. Call:
std::sort(points_vec.begin(), points_vec.end(), compare_points( 1 /*for y*/) );
Sorting by all 3 coords at once:
You have
std:vector<double*> points_vec;
I'm going to presume that the double* points to an array of 3 coordinates. This is cleaner:
std:vector<double(*)[3]> points_vec;
std::sort's third argument is a functor which compares two sequence objects:
bool compare_coords( double(*l)[3], double(*r)[3] ) {
Fortunately, comparing two sequences is already coded for you by std::less:
return std::less( *l, *l + ( sizeof *l/sizeof **l ), r );
(perhaps I did more work than necessary to get the size of the array)
return std::less( *l, *l + 3, r );
}
This function may be useful outside the class, so I'd make it a free function. You need to make it static if it's going to stay inside the class.
Finally, leave off the parens when passing the function to std::sort:
std::sort(points_vec.begin(), points_vec.end(), compare_points );