【问题标题】:C++ const overloaded assignment operator mechanismC++ const 重载赋值运算符机制
【发布时间】:2014-08-16 12:04:29
【问题描述】:

这是来自 '03 或 '04 的 C++ 筛选测试。

以下哪项声明了 MyClass 的赋值运算符,使得第 3 行的代码产生编译错误,而第 2 行的代码没有?

考虑以下代码片段:

   (Line 1) MyClass a, b, c; 
   (Line 2) a=b=c; 
   (Line 3) (a=b)=c; 

1) void operator=( const MyClass& X );
2) MyClass operator=( const MyClass& X );
3) const MyClass operator=( const MyClass& X );
4) None of the above

正确答案是 3)。现在,这是怎么回事?它是如何工作的?什么叫什么? parens 是否强制创建一个临时对象? const 如何参与其中?

【问题讨论】:

  • 一个关于 const 正确性和无用 const 返回值(没有引用)的愚蠢问题
  • 我非常同意,但我没有做出这种攻击的基础。十一年前我弄错了,我不得不知道我当时的感觉是一个“陷阱”,一个小细节,这让我感到被虐待。我今天和现在遇到了它,我想知道。
  • 这是一个人为的情况,但它确实测试了人们对 const、运算符重载和关联性机制的理解程度。也就是说,对他们来说,使用在现实世界中编写实际上有意义的代码示例可能会更好。但也许这就是重点,他们希望你说“正确答案是 3,但这是一个愚蠢的问题。” :)
  • 对于加分,为什么在 C++11 中是个坏主意?
  • 我建议返回引用而不是副本,即 2) MyClass & operator=( const MyClass& X );和 3) const MyClass & operator=( const MyClass& X );

标签: c++ operator-overloading constants assignment-operator c++03


【解决方案1】:

将赋值重写为函数调用而不是运算符可能会有所帮助(正如其他人明确指出的那样,没有任何 (),赋值从右到左进行):

Line 2: a.operator=(b.operator=(c));
Line 3: (a.operator=(b)).operator=(c);

这更清楚地表明,在第 3 行,您正在尝试获取 a=b 的结果并将 c 分配给它。但是在情况 3 中,operator= 的输出是一个 const 对象,所以这是不允许的(因为 operator= 是一个非常量函数)。

将每个分配分成两个单独的语句可能会更清楚:

// with const MyClass MyClass::operator=( const MyClass& X );

// line 1
MyClass a, b, c; 

//line 2; originally a=b=c
const MyClass d = (b = c);
a = d; // no problem; a is nonconst, and it's ok for d (the parameter to operator=) to be const

//line 3; originally (a=b)=c
const MyClass e = (a = b); // note: the leftmost = here is initialization rather than assignment
e = c; // no good! e is const, and you can't call a nonconst function like operator= on a const object

或者更进一步,通过使用名为assign 的函数代替operator= 来消除任何与运算符相关的混乱:

// with const MyClass MyClass::assign( const MyClass& X );

// line 1
MyClass a, b, c; 

//line 2; originally a=b=c
const MyClass d = b.assign(c);
a.assign(d); // ok. assign() is nonconst, but so is a.

//line 3; originally (a=b)=c
const MyClass e = a.assign(b);
e.assign(c); // no good! e is const and assign() is not.

【讨论】:

  • 是的,这有帮助,但我仍然不完全理解。在这两种情况下,a=(b=c) 和 (a=b)=c,是不是有一个 const 对象的赋值,在第一种情况下,由 c 赋值给 b ,而在第二个中通过ca?那么,两者都不应该编译失败吗?
  • 如果选项 3 生效,在a=(b=c) 的情况下,b=c 的返回值确实是 const,但是这个结果(称为 d)然后被用作 输入参数a.operator=(d)。并且参数/右手边允许为 const;只是左侧不是。
  • 在第一种情况下,b=c 的返回值(不是c;代码的编写方式,它是一个临时右值)分配给aa 不是 const,所以没关系。在第二种情况下,您尝试将 c 分配给 a=b 的返回值(同样;这是一个临时的),但该返回值是 const,所以您不能。
  • 很高兴您能理解;猜猜我们的 cmets 有点交错了。
  • 在第二种情况下,在您尝试将c 分配给a=b 的返回值之前,您必须已将b 分配给a。这是允许的,因为它不会被保留,因为它只能用作一次赋值的参数?
【解决方案2】:

赋值是右关联的,所以第 2 行等价于:

a = (b = c);

这意味着必须有一个从MyClassMyClass 的赋值,返回类型可以赋值给MyClass

第二个和第三个选项显然满足了这些要求(就像让编译器生成默认赋值运算符一样)。

第三行虽然要求MyClass 可以分配给MyClassMyClass 的分配的返回值,但只有第二个选项允许,虽然语义不好强>。

结合起来,问题要求选项 3。

赋值运算符应该返回一个对左侧对象的引用,没有任何 cv 限定符,以便正确链接。
阅读本文了解运算符重载的详细信息和背景:Operator overloading

【讨论】:

    【解决方案3】:

    这两行都有 2 个任务。当分成多行语句时,它们看起来像这样:

    Line 2: a=b
            b=c
    Line 3: a=b
            a=c
    

    等号运算符返回左侧。由于选项 3 返回一个 const MyClass,当尝试重新分配一个常量变量时​​,第 3 行将出现错误。

    【讨论】:

      【解决方案4】:

      赋值是右结合的,所以

      a=b=c
      

      等价于

      a=(b=c)
      

      通过使operator=返回一个常量值,你不能再分配给它,所以

      (a=b)=c
      

      不起作用,但这不会影响a=(b=c),因为您正在读取分配的结果而不是写入它。

      【讨论】:

        猜你喜欢
        • 2013-03-30
        • 2016-08-30
        • 1970-01-01
        • 1970-01-01
        • 2018-12-27
        • 2019-11-17
        • 1970-01-01
        • 2012-04-22
        • 2015-06-01
        相关资源
        最近更新 更多