Вы инкапсулируете скаляры? - PullRequest
2 голосов
/ 09 февраля 2009

Я определяю себя как классы:

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 может быть что-то связано?

Обратите внимание, что это не только геометрия, она применима везде. Думаю, посикс socklen_t ...

Ответы [ 2 ]

4 голосов
/ 09 февраля 2009

Я делаю это всякий раз, когда это имеет смысл. Сравните с Как неправильный код выглядит неправильно? Какие шаблоны вы используете, чтобы избежать семантических ошибок? .

На примере статьи Джоэла он обсуждает два случая:

  • Случай веб-приложения, которому необходимо очистить строки перед выводом. Он предлагает типовые префиксы, чтобы различать типы. Однако я утверждаю, что гораздо лучше просто определить два разных типа строк. Самый простой способ сделать это - просто ввести тип SafeString. Только этот тип может быть напрямую отправлен клиенту. Обычный строковый тип должен быть преобразован (явно или неявно; в данном случае это не имеет значения, потому что неявное преобразование все еще может очистить строку).

  • Пример Microsoft Word, где программистам нужно было различать координаты экрана и координаты документа. Это классический случай, когда два разных типа предлагают много преимуществ, хотя эти типы почти идентичны (оба они описывают 2D-точки).

Чтобы устранить ваши недостатки:

Недостаток 1, многословный и неожиданный синтаксис

Большинство языков фактически позволяют перегружать функции / операторы таким образом, чтобы классы использовали ожидаемый синтаксис. В C ++ это даже лучшая практика: «заставляйте свои собственные типы вести себя как int s». Обычно это не требует неявных приведений при наличии соответствующих перегрузок.

Недостаток 2, слишком много классов для каждой вещи, где вы проводите черту?

Сделайте столько пользовательских типов, сколько вам нужно (но не больше). Некоторые языки, такие как Haskell, на самом деле поощряют распространение типов. Единственное, что заставляет нас колебаться в таких языках, как C ++, - это лень, потому что мы должны написать много стандартного кода. C ++ 0x делает это немного проще, вводя псевдонимы типов, безопасные для типов.

Конечно, всегда есть компромисс. Тем не менее, я считаю, что, как только какое-то из преимуществ применимо к вам, этот недостаток просто уравновешен.

1 голос
/ 09 февраля 2009

Я не делаю этого, я нахожу это слишком многословным и сложным из-за крошечных преимуществ, которые оно приносит. Иногда я делаю простой typedef, чтобы было легче читать, но это все.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...