30

我正在阅读一本关于 C++ 的书,更准确地说是关于运算符重载的书。

示例如下:

const Array &Array::operator=(const Array &right)
{
// check self-assignment
// if not self- assignment do the copying
return *this; //enables x=y=z
}

书上提供的关于返回 const ref 而不是 ref 的解释是为了避免像 (x=y)=z 这样的赋值。我不明白我们为什么要避免这种情况。我知道在此示例中首先评估 x=y ,并且由于它返回一个 const 引用,因此 =z 部分无法执行。但为什么?

4

5 回答 5

31

(x=y)手段x.operator=(y),它返回对象x。因此,(x=y)=z意味着(x.operator=(y)).operator=(z)。parens 中的表达式设置xy并返回x,然后外部位设置xz。它并没有像您所期望的那样设置y为,也不像表达式那样设置。zx = y = z

这种行为是违反直觉的(赋值后它们应该都相等,对吧?);返回一个 const 引用使其成为不可能并避免了该问题。

于 2011-01-16T17:04:20.560 回答
22

没有必要避免这一点,除非这本书是针对那些通常(x=y)=z在他们的意思是写的程序员x=y=z。在实践中,没有人在他们正常的头脑中写下这个,所以预防措施是完全没有必要的。它还禁止其他一些简洁的结构,例如(x=y).nonConstMember()几乎没有人写但在某些情况下可能有用的结构(尽管它们不应该被过度使用)。

@ybungalobill 是对的,买一本更好的书。

于 2011-01-16T17:07:17.587 回答
14

据我所知,赋值运算符在惯用的 C++ 中不返回 const 引用。标准类型也不返回 const 引用。

std::string a, b, c;
(a = b).clear(); // no objection from compiler

我所有的自定义赋值运算符都返回了一个非常量引用。

如有疑问,请检查标准库。它不是完美无缺的,但它肯定会正确处理这样的基本问题。

于 2011-01-16T17:18:09.520 回答
4

我会看看内置类型的行为。

在定义自己的类型时,运算符的行为方式最好与内置类型相同。这允许您轻松采用您的类,而无需深入研究您的代码以了解它们的行为与预期不同的原因。

所以如果我们看整数:

int main()
{
    int x = 5;
    int y = 6;
    int z = 7;

    (x = y) = z;
    std::cout << x << " " << y << " " << z << "\n";
}

这适用于 y 不变且 x 被分配 7。在您的代码中,我希望您的分配运算符以相同的方式工作。标准赋值运算符定义:

Array& Array::operator=(Array const& rhs)
{
    /* STUFF */
    return *this;
}

应该这样做就好了(假设 /* STUFF */ 是正确的)。

于 2011-01-16T17:44:32.577 回答
1

我能看到的唯一原因是这本书是为向 C 程序员(或对 C 的理解优于对 C++ 的理解的作者)解释 C++ 而写的。因为对于 C 程序员来说,表达式(x = y) = z对于内置类型是无效的,他可能会尝试使用它的用户定义类型来获得相同的行为。

但是,C 和 C++ 是不同的语言,在 C++ 中,表达式(x = y) = z甚至对内置类型也有效。因此,如果您希望用户定义的类型具有相同的行为,则应在operator =.

我建议你买一本更好的书,一本不会混淆 C 和 C++ 的书。它们不是相同的语言,即使它们来自一个共同的基础。

于 2011-01-16T18:12:42.833 回答