你封装标量吗?

发布于 2024-07-13 12:53:11 字数 1845 浏览 5 评论 0 原文

我发现自己定义的类如下:

struct AngleSize {
    explicit AngleSize(double radians) : size(radians) {}
    double size;
};

与将角度大小存储为普通双精度数相比,这有很多优点。

优点 1,它使得定义这 2 个不同的构造函数成为可能:

Vec2::Vec2(double x, double y);
Vec2::Vec2(double length, AngleSize direction);

...后一个明确地称为 Vec2(1, AngleSize(5));
(尽管在本例中,像 Vec2::fromPolar(1, 5) 这样的静态工厂函数可能也同样好?)

优点 2,它更加类型安全,如下所示错误被发现:

double temperature = air.getTemperature();
Vec2 v(someLength, temperature);

然而一切都还不好。

缺点 1,冗长且意外的语法

Vec2::Vec2(double length, AngleSize direction) {
    x = length * cos(direction.size);
    y = length * sin(direction.size);
}

呃,这实际上应该是 cos(direction),但在不允许不安全的隐式转换的情况下,我需要详细地访问实际值。

缺点 2每件事都有太多的类,你在哪里划清界限?

struct Direction { // angle between line and horizontal axis
    explicit Direction(AngleSize angleSize);
    AngleSize angleSize;
};

struct Angle { // defined by "starting and ending angle" unlike AngleSize
    Angle(Direction startingDir, Direction endingDir);
    Angle(Direction startingDir, AngleSize size);
    Angle(Line line1, Line line2);
};

struct PositionedAngle {
    // angle defined by two rays. this is getting just silly
    PositionedAngle(Ray firstRay, AngleSize angle);
    PositionedAngle(Point center, AngleSize fromAngle, AngleSize toAngle);
    // and so on, and so forth.
};
// each of those being a legit math concept with
// distinct operations possible on it.

在这种情况下,您自己会怎么做?

另外,我在哪里可以阅读有关此问题的信息? 我认为 boost 可能有相关的东西?

请注意,这不仅仅是几何学,它适用于任何地方。 认为 posix socklen_t...

I find myself defining classes like:

struct AngleSize {
    explicit AngleSize(double radians) : size(radians) {}
    double size;
};

This has a bunch of advantages over storing anglesizes as plain doubles.

Advantage 1, it makes it possible to define these 2 distinct constructors:

Vec2::Vec2(double x, double y);
Vec2::Vec2(double length, AngleSize direction);

... the latter one unambigously called as Vec2(1, AngleSize(5));
(though in this case a static factory function like Vec2::fromPolar(1, 5) might have been just as good?)

Advantage 2, it's more typesafe, the following mistake is caught:

double temperature = air.getTemperature();
Vec2 v(someLength, temperature);

Yet all is not fine.

Disadvantage 1, verbose and unexpected syntax

Vec2::Vec2(double length, AngleSize direction) {
    x = length * cos(direction.size);
    y = length * sin(direction.size);
}

Ugh, this should really say cos(direction) yet without allowing an unsafe implicit conversion, I need to verbosely access the actual value.

Disadvantage 2, too many classes for every single thing, where do you draw the line?

struct Direction { // angle between line and horizontal axis
    explicit Direction(AngleSize angleSize);
    AngleSize angleSize;
};

struct Angle { // defined by "starting and ending angle" unlike AngleSize
    Angle(Direction startingDir, Direction endingDir);
    Angle(Direction startingDir, AngleSize size);
    Angle(Line line1, Line line2);
};

struct PositionedAngle {
    // angle defined by two rays. this is getting just silly
    PositionedAngle(Ray firstRay, AngleSize angle);
    PositionedAngle(Point center, AngleSize fromAngle, AngleSize toAngle);
    // and so on, and so forth.
};
// each of those being a legit math concept with
// distinct operations possible on it.

What do you do in such cases, yourself?

Also where can I read about this problem? I think boost might have something related?

Note that this isn't just about geometry, it's applicable everywhere. Think posix socklen_t...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

云淡风轻 2024-07-20 12:53:11

只要有意义,我就会这样做。 与 如何让错误的代码看起来错误? 您使用什么模式来避免语义错误?

在 Joel 文章的示例中,他讨论了两种情况:

  • Web 应用程序需要在输出之前清理字符串的情况。 他提出了类型前缀来区分类型。 然而,我认为简单地定义两种不同的字符串类型要好得多。 最简单的方法就是引入一个 SafeString 类型。 只有这种类型才能直接发送给客户端。 普通字符串类型必须进行转换(显式或隐式;在这种情况下并不重要,因为隐式转换仍然可以清理字符串)。

  • Microsoft Word 示例,程序员需要区分屏幕坐标和文档坐标。 这是典型的案例,其中两种不同的类型提供了很多优势,即使这些类型几乎相同(它们都描述 2D 点)。

解决你的缺点:

缺点1,语法冗长且意想不到

大多数语言实际上允许重载函数/运算符,使类使用预期的语法。 在 C++ 中,这甚至是最佳实践:“让您自己的类型表现得像 int”。 通常,在存在适当重载的情况下,这不需要隐式转换。

缺点2,每件事都有太多的类,你在哪里划清界限?

根据需要创建尽可能多的自定义类型(但不能更多)。 有些语言,例如 Haskell,实际上鼓励类型的扩散。 对于 C++ 这样的语言,唯一让我们犹​​豫的是懒惰,因为我们必须编写大量的样板代码。 C++0x 通过引入类型安全类型别名使这变得稍微容易一些。

当然,总是需要进行权衡。 然而,我相信,只要任何一个优点适用于你,这个缺点就可以被简单地平衡。

I do this whenever it makes sense. Compare with How do you make wrong code look wrong? What patterns do you use to avoid semantic errors?.

In the example of Joel's article he discusses two cases:

  • The case of a web application that needs to sanitize strings before output. He proposes type prefixes to distinguish the types. However, I argue that it's much better to simply define two different string types. The easiest way to do this is just to introduce a SafeString type. Only this type can be directly sent to the client. The normal string type has to be converted (either explicitly or implicitly; it doesn't matter in this case, because the implicit conversion can still sanitize the string).

  • The example of Microsoft Word where the programmers needed to distinguish between screen coordinates and document coordinates. This is the classical case where two distinct types offer a lot of advantages, even though these types are nearly identical (they both describe 2D points).

To address your disadvantages:

Disadvantage 1, verbose and unexpected syntax

Most languages actually allow to overload functions/operators in a way that make classes use expected syntax. In C++, this is even best practice: “make your own types behave like ints.” Usually, this doesn't necessitate implicit casts in the presence of appropriate overloads.

Disadvantage 2, too many classes for every single thing, where do you draw the line?

Make as many custom types as you need (but not more). Some languages, such as Haskell, actually encourage the proliferation of types. The only thing that makes us hesitate in languages like C++ is lazyness because we've got to write a lot of boilerplate code. C++0x makes this slightly easier by introducing type-safe type aliases.

Of course, there's always a trade-off involved. However, I believe that as soon as any one of the advantages apply for you, this disadvantage is simply balanced.

故笙诉离歌 2024-07-20 12:53:11

我不这样做,我会发现它过于冗长和复杂,因为它带来了微小的优势。 我有时会做一个简单的 typedef 以使内容更容易阅读,但仅此而已。

I don’t do this, I’d find it overly verbose and complicated for the tiny advantages it brings. I sometimes do a simple typedef to make things easier to read, but that is all.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文