在设计解决方案时,有时为原始数据类型提供包装类可能是方便的。考虑一个表示数值的类,无论是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
的指针的容器,它应该能够保存任意的值,原始或非原始,并执行可以在Object
上允许的任何原始操作。我希望这样可以更好地解释。
Number
类传递到primitive_increment
中时,您实际上希望该值发生什么?具体而言,当它当前具有非整数值(例如2.5)或超出int
范围的值时会发生什么?在您决定语义之前,无法对此问题提供正确的答案。 - Oliver Charlesworth