关于重载赋值运算符的结果是否为左值的混淆

时间:2016-05-10 12:02:22

标签: c++ c++11 c++03

我有一些疑问,请阅读" Beginning Visual C ++ 2013"书:

  

当您将剩余的赋值操作表示为显式时   重载函数调用,最终变为:

(motto1.operator=(motto2)).operator=(motto3);
     

现在,你有一个从中返回对象的情况   operator=()函数用于调用operator=()函数。如果   返回类型只是CMessage,这不合法,因为a   原始对象的临时副本返回,这将是一个   rvalue 编译器不允许使用成员函数调用   右值。确保这一点的唯一方法是编译并正常工作   是返回一个引用,这是一个左值。

班级CMessage的定义如下:

class CMessage
{
private:
    char* pmessage;

public:
    void ShowIt() const
    {
        cout << endl << pmessage;
    }

    CMessage(const char* text = "Default message")
    {
        cout << endl << "Constructor called.";
        pmessage = new char[strlen(text) + 1];
        strcpy(pmessage, text);
    }

    CMessage(const CMessage& initM)
    {
        cout << "Copy constructor called" << endl;
        pmessage = new char[strlen(initM.pmessage) + 1];
        strcpy(pmessage, initM.pmessage);
    }

    ~CMessage()
    {
        cout << "Destructor called." << endl;
        delete[] pmessage;
    }

    CMessage operator=(const CMessage& aMess)
    {
        delete[] pmessage;
        pmessage = new char[strlen(aMess.pmessage) + 1];
        strcpy(this->pmessage, aMess.pmessage);
        return *this;
    }
};

以及main函数定义为:

int main()
{
    CMessage motto1, motto2;
    CMessage motto3("A miss is as good as a mile.");

    (motto1 = motto2) = motto3;

    motto1.ShowIt();
    motto2.ShowIt();
    motto3.ShowIt();
}

问题:运算符函数是否确实返回了一个右值,或者该书对于该语句是不是很简单?

我的理解是代码存在缺陷,因为在最终结果中,motto1不会被更改,但除此之外它是完全合法的,因为返回的副本(涉及复制构造函数)左值。

2 个答案:

答案 0 :(得分:3)

CMessage operator=(const CMessage& aMess)按值返回。这意味着返回临时对象,(motto1 = motto2)的值类别为 prvalue 。请注意,此处operator=没有什么特别之处,对于按值返回的任何函数都是相同的。

  

我的理解是代码存在缺陷,因为在最终结果中,motto1不会被改变,但除此之外它完全合法,

在ISO C ++中是真的......

  

因为返回的副本(涉及复制构造函数)是左值。

返回的副本是临时对象。 “左值”这个词是表达式的值类别;它不是一个适用于对象的形容词。由函数调用组成的表达式的值类别是 prvalue ,而不是 lvalue

  

编译器不允许使用rvalue进行成员函数调用。

在ISO C ++中,可以在rvalue上调用成员函数。我无法与Visual C ++ 2013对话。

答案 1 :(得分:1)

  

操作符函数是否真的返回了一个右值,或者该书对该语句是不是很简单?

是的,这个特殊重载的运算符确实返回一个值,因此调用表达式的值类别是(p)rvalue。这本书是正确的。

  

我的理解是代码存在缺陷,因为在最终结果中,motto1不会被改变

如果打算将motto3分配给motto1,那么是的,代码确实存在缺陷。但是,这本书的原因是:

  

编译器不允许使用rvalue

进行成员函数调用

不是真的。这对c来说是正确的,并且可能对于c ++的预标准版本,但对于标准c ++则不然。