При разработке решения иногда может быть удобно предоставить классы-оболочки для примитивных типов данных. Рассмотрим класс, представляющий числовое значение, будь то double
, float
или int
.
class Number {
private:
double val;
public:
Number(int n) : val(n) { }
Number(float n) : val(n) { }
Number(double n) : val(n) { }
// Assume copy constructors and assignment operators exist
Number& add(const Number& other) {
val += other.val;
return *this;
}
int to_int() const { return (int) val; }
float to_float() const { return (float) val; }
double to_double() const { return val; }
};
Теперь предположим, что у меня есть функция как таковая:
void advanced_increment(Number& n) {
n.add(1);
}
И я бы использовал эту функцию как таковую:
Number n(2);
advanced_increment(n); // n = 3
Это звучит достаточно просто. Но что, если бы функция была такой?
void primitive_increment(int& n) {
++n;
}
Обратите внимание, что приращение является примером. Предполагается, что функция будет выполнять более сложные операции с примитивными типами данных, которые они также должны иметь возможность выполнять с типами Number
без каких-либо проблем.
Как мне использовать эту функцию точно так же, как раньше? Пример:
Number n(2);
primitive_increment(n);
Как мне сделать мой класс Number
совместимым с primitive_increment
? Как я могу создать класс-оболочку для примитивных типов данных, который был бы совместим везде, где требуются эти типы данных?
На данный момент я нашел только два решения. Один из них - создать такую функцию, как double & Number :: get_value ()
, а затем использовать ее как primitive_increment (n.get_value ());
. Второе решение - создать методы неявного преобразования, такие как Number :: operator int & ()
; но это может привести к множеству неоднозначных вызовов и запутать код.
Мне интересно, есть ли другое решение для реализации этих типов оболочек и сохранения их примитивной функциональности.
Обновление:
Для дальнейшего пояснения, в реальном проекте намерение состоит в том, чтобы сделать все типы данных производными от одного базового класса, который обычно упоминается как Объект
при разработке такого решения. Ограничение заключается в том, что нельзя использовать внешнюю библиотеку. Следовательно, если у меня есть контейнер с указателями на тип Object
, он должен иметь возможность хранить любое произвольное значение, примитивное или нет, и выполнять любые примитивные операции, разрешенные для Object
]. Надеюсь, это лучше объясняет.