为什么需要两个函数重载运算符?

3

我目前正在为我的其中一个课程使用C++动态内存编写双向链表。我已经写好了代码,只是有一个问题。

我们的教授要求我们同时编写一个

int& operator[](int position) 

并且一个

int operator[](int position) const

函数。

为什么要针对同一运算符编写两个函数?我相信这背后肯定有某种逻辑,哈哈。是为了让我既可以执行 a = arr[i],也可以执行 arr[i] = a 吗?

6个回答

4

如果你有一个const列表对象,那么你只能从中读取值。如果你有一个可修改的对象,那么你既可以读取值,也可以写入值。第一种情况使用const版本来实现,该版本将应用于const对象。


1
但既然const函数的功能也包含在其他函数中,为什么还要写它呢?这只是为了让编译器在代码更改数据时提醒你吗? - UnclosedParenthesis
1
@user2816987,这并不适用于非const变量,因为它不能在const对象上调用。 - Konrad Rudolph
@user2816987:我在我的回答中尝试解释为什么要这样做。不清楚吗? - László Papp
@LaszloPapp - 你可以拥有一个该列表类型的const对象,如果这样做,编译器将不允许您在该对象上调用非const成员函数。C++编程的一个重要方面是常量正确性:不应修改对象的函数不应该能够修改它。因此,只查看array对象内容的函数应通过const引用来获取该对象,例如void show(const list&)。您可以使用可修改的list对象调用该对象;编译器不会让函数修改该对象。这是一件好事:更容易找到不正确的更改。 - Pete Becker
我不确定你在这篇文章中想要达到什么目的。 - László Papp
@LaszloPapp - 你问了“为什么要费心”。我告诉你,是因为常量正确性。 - Pete Becker

1
当你的对象是const时,你只能使用运算符的const版本,这个版本由于是const,所以不允许修改你的对象或返回指向内部成员的非const指针/引用。因此,当你的对象是非const时,你需要一个允许修改的非const运算符,这样你就可以写foo[i]=n

0
这是为了让我既可以执行a = arr[i],也可以执行arr[i] = a,对吗?
是的,就是为此而设计的。
  • 如果你有一个const或非const列表,那么你可以执行a = arr[i]赋值;
  • 返回一个int&类型的运算符版本是为了让你能够执行arr[i] = a,当然这需要一个非const列表。

@LightnessRacesinOrbit - 不行,它无法编译。如果operator[]返回int,则无法将结果分配给arr[i] - Pete Becker
@PeteBecker:不行,它不能。struct T { int operator[](int) { return 3; } }; int main() { T t; t[5] = 2; } => error: lvalue required as left operand of assignment - Lightness Races in Orbit
@PeteBecker:没错,你一开始声称可以做到,现在又承认做不到。你到底想说什么? - Lightness Races in Orbit
@PeteBecker:啊,将s/can/can't/应用于您的第一条评论,您就指出了我答案中的一个缺陷。现在发现了。谢谢! - Lightness Races in Orbit
非“const”版本返回“int&”,因此可以将其赋值给结果。“const”版本返回“int”,您不能对该结果进行分配。 - Pete Becker
@PeteBecker:是的,我知道——我在前面的几条评论中已经演示过了! - Lightness Races in Orbit

0

1) const 变量用于读取,例如当您将一个值分配给一个变量时。如果尝试修改指定索引处的列表值,编译器将会报错。例如,如你所写的 a = arr[i]

2) 非 const 版本通常用于实际设置列表中某个索引处的值。虽然您也可以使用这种版本来获取值,但是当您的意图只是读取时,编译器不会引发错误。这可能会导致微妙的错误,而您可以通过在这些情况下使用 const 来避免此类问题。例如,如你所写的 arr[i] = a

如果您同时拥有两个版本,则在对非 const 对象执行索引操作时,将调用非 const 版本进行读取。


0

如果你有一个对象的常量变量,比如说 A const a;,那么你只能调用常量函数,比如你的 operator [] (...) const 的常量重载,它只提供读取操作。在这种情况下,你不能调用非常量的 operator [] (...)


0

当你有一个使用const限定符定义的双向链表对象(通常称为“const对象”)或通过指向const或引用const的指针引用时,你希望能够读取但不能写入。使用const限定符的运算符可以实现这一点。

当你有一个没有使用const限定符定义的对象,或通过指向非const或引用非const的指针引用时,你希望能够进行读写操作。使用非const限定符的运算符可以实现这一点。

因此,编写两个重载函数的原因是为了实现这两种行为。

如果你只想要读取,而不考虑是否为const,那么你只需要编写const版本,因为const限定的成员函数可以与两种情况交互,而非const限定的成员函数只能用于非const限定对象的名称(或通过指向非const或引用非const的指针)。

如果您只想让operator[]应用于非const对象,那么您只需要编写非const限定版本。这可能看起来很奇怪,因为您不希望operator[]需要对对象进行修改,但事实上,这正是std::map使用operator[]的方式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接