vsurendhaaren Ответов: 4

Наследование примитивных типов данных в C++


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

Первоначальная задача состоит в том, чтобы определить переменную, содержащую дисперсию, и сделать ее безопасной для типа. Я не хочу утверждать, что значение не становится отрицательным каждый раз, когда переменная испорчена. Я хочу, чтобы это делалось автоматически. Я рассматривал реализацию свойств (найденную в проекте кода) для C++, но это кажется слишком большим для реализации простого условного двойника.

Sergey Alexandrovich Kryukov

Очень хороший вопрос, мой 5. Такой подход имеет смысл (если только он не является чрезмерным для этой цели).
--СА

4 Ответов

Рейтинг:
30

Espen Harlinn

В духе идеи Алена Риста:

#include <cmath>

template<typename T>
class Primitive
{
private:
    T _var;
public:
    Primitive(const T& var)
        : _var(std::abs(var))
    {}

    operator T ()
    {
        return _var;
    }

    Primitive& operator = (const T& var)
    {
        _var = std::abs(var);
        return *this;
    }
};

typedef Primitive<double> DoublePrimitve;
typedef Primitive<long> LongPrimitve;
typedef Primitive<__int64> LongLongPrimitve;
typedef Primitive<long double> LongDoublePrimitve;
typedef Primitive<float> FloatPrimitve;


Теперь вы даже можете повторно использовать импликацию :)

С уважением
Эспен Харлинн


Sergey Alexandrovich Kryukov

Мой 5. Так хорошо в C++ можно использовать такие шаблоны.
--СА

Espen Harlinn

Спасибо Сакрюкову - наверное, вы имели в виду "не могу" и не " могу" :)

Sergey Alexandrovich Kryukov

Нет, я имел в виду "C++ can", теперь измененный, благодаря вашей записке.
Я не мог бы с полным правом сказать, что C# не может, потому что это .NET виноват.
И это связано с отсутствием наследования примитивных типов, как я уже утверждал.
--СА

vsurendhaaren

Эспен, Спасибо, что показал, что он может быть расширен до любого примитива.

Espen Harlinn

Рад, что тебе понравилось :)

Рейтинг:
24

Alain Rist

Привет,
Предыдущие ответы показывают, что ваш подход не подходит к вашей проблеме. Использовать для управления вашим значением, например:

struct Variance
{
    Variance(long double var) : _var(std::abs(var))
    {}
    operator long double ()
    {
        return _var;
    }
    Variance& operator = (const long double& var)
    {
        _var = std::abs(var);
        return *this;
    }
private:
    long double _var;
};

С operator long double () в этом нет необходимости переопределить все возможные операторы.
овации,
АР


Espen Harlinn

Мой 5, Хороший и простой

vsurendhaaren

Большое спасибо, Ален. Это работает идеально.

Рейтинг:
1

Sergey Alexandrovich Kryukov

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

Возвращаясь к C++ и вашей оболочке, вам действительно нужно объединить все арифметические операции между оболочками, а также между оболочками и примитивным числовым типом. (Это вы упомянули грязного? Другого пути нет). Что приводит к вопросу: какова дополнительная функциональность? Это просто ограничения, я использовал другой подход.

Некоторое время назад я разработал архитектуру meta-data Engine (MDE), мы разработали реализацию с командой (на C++), а также коммерческий программный продукт с использованием движка. Одна из целей состояла в том, чтобы заменить многие скучные классы данных их метамоделями, которые автоматически создавали рутинные структуры данных. Одной из небольших частей движка была поддержка доменов данных на уровне meta2, а Домены определяли примитивные типы, включая ограничения (такие как кратность, которая является ограничением для мощности).

Видите ли, когда вы обертываете свой двойной тип данных, вы смешиваете его значение (data, meta⁰-data) с meta1-данными, такими как constraint. Вы можете уйти от этого, если создадите универсальные структуры данных (например, неограниченное количество строковых, целочисленных, булевых, перечислительных и плавающих свойств). Содержание структуры и правила управляются meta1-данными (имена свойств, описания, ссылки на домены и, возвращаясь к сути, ограничения). Каждый экземпляр структуры данных meta⁰-data сохраняет ссылку на свой тип meta1-data. Универсальное правило для работы с универсальными структурами данных использует ограничения.

—СА


Espen Harlinn

Хороший ответ, мой 5

Sergey Alexandrovich Kryukov

- Спасибо, Эспен.
Это скорее намек; очень трудно объяснить подход вкратце.
--СА

Рейтинг:
1

Kythen

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

Если это значение дисперсии само по себе является членом только одного или двух других классов и не используется независимо, как класс или структура, то я бы рассмотрел просто использование double (или другого подходящего числового типа) и управление доступом к нему через функции, которые проверяют значение.