4

C++ FAQ正在定义一个模板容器Matrix以避免棘手的new delete代码。教程说下标运算符经常成对出现?为什么会这样?

T&       operator() (unsigned i, unsigned j); 
T const& operator() (unsigned i, unsigned j) const;

为什么会这样?

这也称为:常量重载。

常见问题解答提供线索。您还有其他意见吗?

特别是,是否应该mutate()遵守某些规则才能安全地仅用于 const 对象?

4

2 回答 2

8

简而言之,因为作业有两个方面:左侧和右侧。

非常量版本:T& operator() (unsigned i, unsigned j);主要用于赋值的左侧(即,用作赋值的目标)。

const 版本:T const& operator() (unsigned i, unsigned j) const;专门用于赋值的右侧。

注意这里的措辞不同:const 版本只能用在赋值的右边,而非 const 版本可以用在两边。但是,如果您有一个const-qualified 对象,则只能调用 const 限定的成员函数,因此在这种情况下根本无法使用它。这正是您(至少通常)想要的——它可以防止修改您说过不应该修改的对象(通过 const 限定它)。

就目前而言,它通常仅用于在逻辑状态和按位mutate状态之间存在差异的对象。一个常见的例子是一个懒惰地做一些(通常是昂贵的)计算的类。为了避免重新计算该值,它会在计算后保存该值:

class numbers { 
    std::vector<double> values;
    mutable double expensive_value;
    bool valid;
public:
    numbers() : valid(false) {}

    double expensive_computation() const { 
        if (valid) return expensive_value;
        // compute expensive_value here, and set `valid` to true
    }
};

所以在这里,结果expensive_computation完全取决于 中的值values。如果您不关心速度,则可以在每次用户调用时重新计算该值expensive_computation。在一个 const 对象上重复调用它总是会产生相同的结果——所以调用它一次后,我们假设它可能会被再次调用,为了避免重复执行相同的昂贵计算,我们只需将值保存到expensive_value. 然后,如果用户再次请求它,我们只需返回该值。

换句话说,从逻辑的角度来看,const即使我们修改了expensive_value. 对象的可见状态不会改变。我们所做的只是让它更快地完成 const 的事情。

为了使其正常工作,我们还希望valid在用户修改values. 例如:

void numbers::add_value(double new_val) {
   values.push_back(new_val);
   valid = false;
}

在某些情况下,我们可能还需要一个中间级别的有效性——我们可能能够通过(例如)确切地知道哪些数字已被添加到 中,而不是仅仅使用布尔值来说明它是否是当前的,expensive_value从而更快地重新计算values有效与否。

我可能应该补充一点,C++11 对constmutable. 长话短说,在大多数情况下,您需要确保任何是const和/或mutable也是线程安全的。您可能想观看Herb Sutter 的视频。然而,我确实觉得有必要补充一点,我认为他的结论mutable可能有点夸张(但我宁愿你自己观看并决定,而不是相信我的话)。

于 2013-03-15T15:23:02.237 回答
2

在对象上调用下标运算符,调用T&第一个非常量运算符。然后,允许检查和变异操作。

在对象上调用下标运算符,T const &调用第二个 const 运算符。然后,允许检查,但不允许变异。

例子在这里

void f(MyFredList const& a)  ← the MyFredList is const
{
  // Okay to call methods that DON'T change the Fred at a[3]:
  Fred x = a[3];
  a[3].inspect();

  // Error (fortunately!) if you try to change the Fred at a[3]:
  Fred y;
  a[3] = y;       ← Fortunately(!) the compiler catches this error at compile-time
  a[3].mutate();  ← Fortunately(!) the compiler catches this error at compile-time
}

归功于 C++ 常见问题解答,更多信息请点击此处

于 2013-03-15T15:06:50.140 回答