我目前正在为我的其中一个课程使用C++动态内存编写双向链表。我已经写好了代码,只是有一个问题。
我们的教授要求我们同时编写一个
int& operator[](int position)
并且一个
int operator[](int position) const
函数。
为什么要针对同一运算符编写两个函数?我相信这背后肯定有某种逻辑,哈哈。是为了让我既可以执行 a = arr[i],也可以执行 arr[i] = a 吗?
我目前正在为我的其中一个课程使用C++动态内存编写双向链表。我已经写好了代码,只是有一个问题。
我们的教授要求我们同时编写一个
int& operator[](int position)
并且一个
int operator[](int position) const
函数。
为什么要针对同一运算符编写两个函数?我相信这背后肯定有某种逻辑,哈哈。是为了让我既可以执行 a = arr[i],也可以执行 arr[i] = a 吗?
如果你有一个const
列表对象,那么你只能从中读取值。如果你有一个可修改的对象,那么你既可以读取值,也可以写入值。第一种情况使用const
版本来实现,该版本将应用于const
对象。
const
版本,这个版本由于是const,所以不允许修改你的对象或返回指向内部成员的非const指针/引用。因此,当你的对象是非const时,你需要一个允许修改的非const运算符,这样你就可以写foo[i]=n
。a = arr[i]
,也可以执行arr[i] = a
,对吗?const
或非const
列表,那么你可以执行a = arr[i]
赋值;int&
类型的运算符版本是为了让你能够执行arr[i] = a
,当然这需要一个非const
列表。operator[]
返回int,则无法将结果分配给arr[i]
。 - Pete Beckerstruct T { int operator[](int) { return 3; } }; int main() { T t; t[5] = 2; }
=> error: lvalue required as left operand of assignment
- Lightness Races in Orbits/can/can't/
应用于您的第一条评论,您就指出了我答案中的一个缺陷。现在发现了。谢谢! - Lightness Races in Orbit1) const
变量用于读取,例如当您将一个值分配给一个变量时。如果尝试修改指定索引处的列表值,编译器将会报错。例如,如你所写的 a = arr[i]
。
2) 非 const 版本通常用于实际设置列表中某个索引处的值。虽然您也可以使用这种版本来获取值,但是当您的意图只是读取时,编译器不会引发错误。这可能会导致微妙的错误,而您可以通过在这些情况下使用 const
来避免此类问题。例如,如你所写的 arr[i] = a
。
如果您同时拥有两个版本,则在对非 const 对象执行索引操作时,将调用非 const 版本进行读取。
如果你有一个对象的常量变量,比如说 A const a;
,那么你只能调用常量函数,比如你的 operator [] (...) const
的常量重载,它只提供读取操作。在这种情况下,你不能调用非常量的 operator [] (...)
。
当你有一个使用const
限定符定义的双向链表对象(通常称为“const对象”)或通过指向const
或引用const
的指针引用时,你希望能够读取但不能写入。使用const
限定符的运算符可以实现这一点。
当你有一个没有使用const
限定符定义的对象,或通过指向非const
或引用非const
的指针引用时,你希望能够进行读写操作。使用非const
限定符的运算符可以实现这一点。
因此,编写两个重载函数的原因是为了实现这两种行为。
如果你只想要读取,而不考虑是否为const
,那么你只需要编写const
版本,因为const
限定的成员函数可以与两种情况交互,而非const
限定的成员函数只能用于非const
限定对象的名称(或通过指向非const
或引用非const
的指针)。
如果您只想让operator[]
应用于非const
对象,那么您只需要编写非const
限定版本。这可能看起来很奇怪,因为您不希望operator[]
需要对对象进行修改,但事实上,这正是std::map
使用operator[]
的方式。
const
变量,因为它不能在const
对象上调用。 - Konrad Rudolphconst
对象,如果这样做,编译器将不允许您在该对象上调用非const
成员函数。C++编程的一个重要方面是常量正确性:不应修改对象的函数不应该能够修改它。因此,只查看array
对象内容的函数应通过const
引用来获取该对象,例如void show(const list&)
。您可以使用可修改的list
对象调用该对象;编译器不会让函数修改该对象。这是一件好事:更容易找到不正确的更改。 - Pete Becker