4

我使用两个Points 来定义 aLine和 a LineSegment,例如:

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

LineSegment与 具有相同的定义Line,所以我一开始使用typedef Line LineSegment而不是定义另一个LineSegment类。但是很快,我发现我无法定义函数distance来计算点与线或点与线段之间的距离。

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) { ... }

当然我会得到一个编译错误。

所以,我的问题是:有没有更好的方法来区分Line没有LineSegment重新定义LineSegment

4

2 回答 2

3

我遵循@Amadan的建议。创建一个抽象类。

#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);
}
于 2013-07-11T01:31:36.593 回答
2

一条线段有一个起点和一个终点,而一条线可能仅由其上最接近原点的点(或其他一些表示)唯一地定义。

所以 Line 表示要么是无效的,要么是过度的。

编辑:啊哈,我知道我错过了一些东西!如果使用最接近原点的直线上的点 (x, y),那么斜率为 (–x/y),并且可以很容易地在 (x+y, y–x) 处构造直线上的第二个点. 因此,Line 的实现可以计算它以使用临时对象将操作委托给 LineSegment,其成本低于从内存中加载额外值的成本。(临时的应该完全存在于寄存器中。)

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(); }
};

(呃......现在我写了所有我能看到的,实际上你希望委托在这里走另一条路,并减去 LineSegment 的坐标以产生正确角度的 Line。无论如何,这有效,你明白了。这样委托可以双向进行,而继承通常是单向的。)


此外,您不应该typedef仅仅因为里面的数据成员相似而发生事情。为什么不把它们都输入到数组中呢?一个类代表一个不同的概念。

我建议反对 AbstractLine 建议,除非有有意义的方法可以放入其中。从界面开始,用最方便的方式填写内部细节。类不应该仅仅因为它们看起来相同就共享实现,而是因为实现在概念上做同样的事情。

因为数学很棘手,所以应该编写数学类以允许更改内部表示,并且公共继承有点危险。因为数学不涉及“参与者”和动作,而是涉及具有交换性等属性的通用操作,所以 OOP 通常不适合。

于 2013-07-11T01:33:54.207 回答