您的代码看起来很棒,就好像您习惯了另一种语言一样——在 C++ 中使用this->x
(例如)相对不寻常。当代码写得很好时,使用访问器或修改器也是如此。
虽然我在这方面相当不寻常,但我会继续记录(再次)说,强制客户端代码直接使用访问器或修改器是一个坏主意。如果您确实遇到客户端代码操作对象中的值有意义的情况,那么客户端代码应该使用正常赋值来读取和/或写入该值。
当/如果您需要控制分配的值时,运算符重载可以让您进行控制,而不会在客户端代码上强制使用丑陋的 get/set 语法。具体来说,您想要的是一个代理类(或类模板)。仅举一个例子,人们想要获取/设置函数的最常见情况之一是应该限制在某个特定范围内的数字。检查新setXXX
值是否在范围内,然后getXXX
返回该值。
如果你想要这样,一个(相当)简单的模板可以更干净地完成这项工作:
template <class T, class less=std::less<T> >
class bounded {
const T lower_, upper_;
T val_;
bool check(T const &value) {
return less()(value, lower_) || less()(upper_, value);
}
void assign(T const &value) {
if (check(value))
throw std::domain_error("Out of Range");
val_ = value;
}
public:
bounded(T const &lower, T const &upper)
: lower_(lower), upper_(upper) {}
bounded(bounded const &init)
: lower_(init.lower), upper_(init.upper)
{
assign(init);
}
bounded &operator=(T const &v) { assign(v); return *this; }
operator T() const { return val_; }
friend std::istream &operator>>(std::istream &is, bounded &b) {
T temp;
is >> temp;
if (b.check(temp))
is.setstate(std::ios::failbit);
else
b.val_ = temp;
return is;
}
};
这也使得代码更接近于自我记录——例如,当你声明一个像这样的对象时bounded<int>(1, 1024);
,很明显意图是一个 1 到 1024 范围内的整数。有人可能会发现有问题的唯一部分是范围内是否包含 1 和/或 1024。这与在类中定义一个 int 有很大不同,并且期望每个看过该类的人都意识到他们应该使用 setXXX 来强制对可以是分配的。
当您将其中一个嵌入到一个类中时,您将其设为公共变量,并且仍然强制执行该范围。在客户端代码中,语法没有真正的争论——你只是分配给一个公共变量,就像你做任何其他的一样——尝试分配一个超出范围的值会引发异常的次要细节。从理论上讲,该类可能应该采用策略模板参数来准确指定它在这种情况下的作用,但我从来没有真正的理由为此烦恼。