How to distinguish class LineSegment from Line?

I use two Point to define a Line , as well as a LineSegment , for example:

 class Point { ... }; class Line { Point p1, p2; //... }; class LineSegment { Point p1, p2; //... }; 

LineSegment has the same definition as Line , so I first used the typedef Line LineSegment instead of defining another LineSegment class. But I soon discovered that I could not define the distance function 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) { ... } 

Of course, I will get a compilation error.

So my question is: Is there a better way to distinguish Line from LineSegment without overriding LineSegment ?

+4
source share
2 answers

I follow @Amadan's suggestion. Create an 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); } 
+3
source

A line segment has a start point and an end point, while a line can be uniquely determined only by the point on it closest to the origin (or some other representation).

Therefore, the Line representation is invalid or excessive.

Edit: Yeah, I knew something was missing! If you use a point on the line closest to the origin (x, y), then the slope is (-x / y), and the second point on the line can easily be built on (x + y, yx), Thus, the implementation of Line can calculate that delegation of LineSegment operations using a temporary object is less expensive than loading additional values ​​from memory. (Temporary must reside fully in registries.)

 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 have written everything that I see that you really want the delegation to go the other way, and subtract the coordinates of LineSegment to create the line at the right angle. In any case, this works, and you get Such delegation can go both ways, while inheritance is usually a one-way street.)


Also, you shouldn't typedef things just because the data members inside are similar. Why not just overlay them on arrays? A class is a clear concept.

I recommend against the AbstractLine suggestion if it has no meaningful methods. Start with the interface and fill in the internal details in the most convenient way. Classes should not share an implementation just because they look the same, but because implementations do conceptually the same thing.

Because math is complex, math classes must be written to allow changes in internal representations, and public inheritance is a little dangerous. Since math does not include “actors” and actions, but rather general operations with properties such as commutativity, OOP is often not well suited for everyone.

+2
source

Source: https://habr.com/ru/post/1490821/


All Articles