【问题标题】:Why isn't the read only [] operator used?为什么不使用只读 [] 运算符?
【发布时间】:2017-01-19 10:28:48
【问题描述】:

我目前正在用 C++ 编写一个Polynomial-class,它应该表示以下形式的多项式:

p(x) = a_0 + a_1*x^1 + a_2*x^2 + ... + a_i*x^i

其中a_0, ..., a_i 都是int 的。

该类内部使用std::vector<int> 类型的成员变量a_ 来存储常量因子a_0, ..., a_i。要访问常量因子,operator[] 以下列方式重载:

读写:

int &operator[](int i)
{
  return a_.at(i);
}

当试图改变其中一个因素a_i 时,这将失败:

i > degree of polynomial = a_.size() - 1

只读:

int operator[](int i) const
{
  if (i > this->degree()) {
    return 0;
  }

  return a_.at(i);
}

略有不同的实现允许对两个不同大小的多项式的因子进行相当舒适的循环(无需担心多项式的次数)。

遗憾的是,我似乎在这里错过了一些东西,因为 operator+-overloading(利用这种舒适的只读-operator[])失败了。

operator+-overloading

Polynomial operator*(const Polynomial &other) {
  Polynomial res(this->degree() + other.degree());

  for (int i = 0; i <= res.degree(); ++i) {
    for (int k = 0; k <= i; ++k) {
      res[i] += (*this)[k] * other[i-k];
    }
  }

  return res;
}

不要介意所涉及的数学。重要的一点是,i 始终在范围内

0 <= i < res.a_.size()

因此写入res[i] 是有效的。但是(*this)[k]other[i-k] 尝试从不一定位于[0, (*this).a_.size() - 1] 范围内的索引中读取。

这对于我们的只读-实现operator[] 应该没问题,对吧?尝试在无效索引处访问 a_ 时仍然出错。什么可能导致编译器在行中使用 read-write-实现:

res[i] += (*this)[k] * other[i-k]; 

尤其是等号右边的部分。

我确定该错误是由 read-and-write-operator[] 的“错误”使用引起的。因为通过额外的检查修复了无效访问:

if (k <= this->degree() && i-k <= other.degree()) {
  res[i] += (*this)[k] * other[i-k];
}

使用operator[]-overloading 我缺少什么?为什么这里不使用只读-operator[]

【问题讨论】:

  • 二进制operator* 通常应该是const
  • [ ] 做不同的事情是违反直觉和令人困惑的。程序员期待同样的行为。
  • 首选非会员 Polynomial operator*(Polynomial const&amp; lhs, Polynomial const&amp; rhs),因为您不需要对 this 的任何特权访问。是的,at 会比神奇的 [] 更好,它有时会做你想做的事......
  • 这个问题是一个很好的例子,说明完全没有尝试将代码缩小到相关部分。
  • 但是你有没有问过自己读者是否想通读所有的上下文?我的意思是,这个问题写得很好,读起来很有趣,但是到最后,我现在可以想象一个十行版本的问题,它表达了同样的观点,我希望这就是那个问题。很抱歉选择了你,但很少看到有这个问题但总体上很好的问题。 (通常这个问题出现在完全没有希望的问题中。)

标签: c++ operator-overloading operators readonly read-write


【解决方案1】:

(*this)[k] 使用非常量 this,因为包含它的函数不是 const

因此,编译器首选 [] 的非常量重载。

你可以使用丑陋的const_cast 来解决这个问题,但实际上你应该保持[] 运算符的两个版本的行为尽可能相似。此外,[]std::vector 重载并不坚持要检查索引,而不是必须检查的 at。您的代码与此有偏差,因此可能会使您的代码的读者感到困惑。

【讨论】:

  • 非常感谢。实际上operator* 重载是const,因此不需要const_cast。我会尽快接受答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-30
  • 1970-01-01
  • 2017-02-12
  • 1970-01-01
  • 2020-12-12
  • 2016-06-01
相关资源
最近更新 更多