【问题标题】:Overloading operators "=" and "+" do not work when combined in C++重载运算符“=”和“+”在 C++ 中组合时不起作用
【发布时间】:2015-03-14 04:10:57
【问题描述】:
#include <iostream>
using namespace std;
class A
{
public:
    A(int a)
    {
        length = a;
    }
    ~A(){}

    friend A operator +(A& var1, A& var2);
    A& operator=(A &other);

    int length;
};

A operator +(A& var1, A& var2)
{
    return A(var1.length + var2.length);
}

A& A::operator=(A &other)
{
    length = other.length;
    return *this;
}


int main()
{
    A a(1);
    A b(2);
    A c(3);
    c = a;   // work
    c = a + b;  // does not work
    cout << c.length ;
    return 0;
}

在 main() 中,c = a 已成功编译,但 "c = a + b" 未成功编译。 但是,在 A& A::operator=(A &other) 中,如果我将 (A &other) 更改为 (A other) 则它可以工作。 谁能帮我处理这个案子?

【问题讨论】:

    标签: c++ class operator-overloading overloading


    【解决方案1】:

    最简单的解决方法是让你的赋值重载通过 const 引用获取它的参数。

    那么a + b返回的临时值就可以和它一起使用了。

    A& A::operator=(A const & other)
    {
        length = other.length;
        return *this;
    }
    

    您可能希望对您的 operator+ 执行相同的操作,以便 c = a + a + a; 也能正常工作。

    【讨论】:

    • 感谢您的回答。但是,我仍然不明白为什么你的方式有效。据我所知,a + b 将返回一个对象 A,那么在 A&A::operator=(A const & other) 中不使用“const”和使用“const”有什么区别?顺便说一句,我从未见过像这样在类名之后使用“const”。你能给我解释一下吗?谢谢。
    • @MrCold:A const&amp;const A&amp; 之间没有区别。同样,A const*const A* 相同。但是A* const 是完全不同的野兽。
    • @MrCold 不同之处在于 C++ 不允许您将非 const 引用绑定到临时引用,例如 a + b 返回的 A。相反,如果operator= 的参数是const 引用,它 允许绑定的。 C++ 阻止非const 引用绑定的原因只是它使代码可以轻松修改即将被销毁的值 - 更改后的状态不会做任何事情,所以它被认为是“代码气味”,通常表示编程错误,尽管偶尔会有用。
    • A &amp;A::operator=(A other) 的优点是复制赋值和移动赋值合二为一。
    • @MattMcNabb 缺点是它的实现不是很好。
    【解决方案2】:

    问题是operator +返回一个临时对象

    friend A operator +(A& var1, A& var2);
    

    但临时对象可能不会绑定到作为赋值运算符的参数类型的非常量引用。

    A& operator=(A &other);
    

    所以编译器对语句发出错误

    c = a + b;
    

    你有三种可能。

    第一个将复制赋值运算符的参数声明为常量引用的os

    A& operator=(const A &other);
    

    这是最简单的方法。

    第二种是声明一个移动赋值操作符而不是复制赋值操作符。在这种情况下,您还需要明确定义一个复制或移动构造函数。在这种情况下,而不是

    c = a;
    

    你必须写

    c = std::move( a );   // work
    

    例如

    #include <iostream>
    using namespace std;
    class A
    {
    public:
        A(int a)
        {
            length = a;
        }
        ~A(){}
    
        friend A operator +(A& var1, A& var2);
        A& operator=(A &&other);
        A( A && ) = default;
        int length;
    };
    
    A operator +(A& var1, A& var2)
    {
        return A(var1.length + var2.length);
    }
    A& A::operator=(A &&other)
    {
        length = other.length;
        return *this;
    }
    
    int main()
    {
        A a(1);
        A b(2);
        A c(3);
        c = std::move( a );   // work
        c = a + b;  // does not work
        cout << c.length ;
        return 0;
    }
    

    最后你可以同时拥有这两个运算符。例如

    #include <iostream>
    using namespace std;
    class A
    {
    public:
        A(int a)
        {
            length = a;
        }
        ~A(){}
    
        friend A operator +(A& var1, A& var2);
        A& operator=(const A &other);
        A& operator=(A &&other);
        A( const A & ) = default;
        int length;
    };
    
    A operator +(A& var1, A& var2)
    {
        return A(var1.length + var2.length);
    }
    
    A& A::operator=(const A &other)
    {
        length = other.length;
        return *this;
    }
    
    A& A::operator=(A &&other)
    {
        length = other.length;
        return *this;
    }
    
    int main()
    {
        A a(1);
        A b(2);
        A c(3);
        c = a;   // work
        c = a + b;  // does not work
        cout << c.length ;
        return 0;
    }
    

    在这种情况下在语句中

        c = a;   // work
    

    这里会调用复制赋值操作符和in语句

        c = a + b;  // does not work
    

    这里将调用移动赋值运算符。

    当然,您也可以同时拥有复制构​​造函数和移动构造函数,就像复制赋值运算符和移动赋值运算符一样。对于您的班级,您可以将它们全部定义为默认值。 例如

    #include <iostream>
    using namespace std;
    class A
    {
    public:
        A(int a)
        {
            length = a;
        }
        ~A(){}
    
        friend A operator +(A& var1, A& var2);
        A& operator=(const A &other) = default;
        A& operator=(A &&other) = default;
        A( const A & ) = default;
        A( A && ) = default;
        int length;
    };
    
    A operator +(A& var1, A& var2)
    {
        return A(var1.length + var2.length);
    }
    
    
    int main()
    {
        A a(1);
        A b(2);
        A c(3);
        c = a;   // work
        c = a + b;  // does not work
        cout << c.length ;
        return 0;
    }
    

    【讨论】:

    • 您将“移动”带入画面,使事情变得不必要地复杂。 OP 只是试图创建一个没有指针的简单值类型 - move 没有用,可能会隐藏问题,但不是一个好的解决方法。
    • @Tony D 在我看来,你完全错了,我只是对这个问题进行了一般性的观察。它总是比某种解决方案更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-22
    • 1970-01-01
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 2021-12-09
    • 1970-01-01
    相关资源
    最近更新 更多