【问题标题】:assignment operator overloading in c++C++中的赋值运算符重载
【发布时间】:2012-04-22 00:11:01
【问题描述】:

我使用以下代码进行赋值运算符重载:

SimpleCircle SimpleCircle::operator=(const SimpleCircle & rhs)
{
     if(this == &rhs)
        return *this;
     itsRadius = rhs.getRadius();
     return *this;
}

我的复制构造函数是这样的:

SimpleCircle::SimpleCircle(const SimpleCircle & rhs)
{
    itsRadius = rhs.getRadius();
}

在上面的运算符重载代码中,复制构造函数被调用,因为正在创建一个新对象;因此我使用了以下代码:

SimpleCircle & SimpleCircle::operator=(const SimpleCircle & rhs)
{
    if(this == &rhs)
       return *this;
    itsRadius = rhs.getRadius();
    return *this;
}

它工作得很好并且避免了复制构造函数问题,但是关于这个(对我来说)有什么未知的问题吗?

【问题讨论】:

  • @Praetorian 如果您知道在赋值运算符期间可能会抛出一个项目,或者如果您正在使用尚未开发的软件并且不知道是否会发生抛出,则复制和交换习语很好.如果您正在使用自己的项目,并且您知道使用复制和交换习语不会引发任何错误。

标签: c++ operator-overloading


【解决方案1】:
#include<iostream>

using namespace std;

class employee
{
    int idnum;
    double salary;
    public:
        employee(){}

        employee(int a,int b)
        {
            idnum=a;
            salary=b;
        }

        void dis()
        {
            cout<<"1st emp:"<<endl<<"idnum="<<idnum<<endl<<"salary="<<salary<<endl<<endl;
        }

        void operator=(employee &emp)
        {
            idnum=emp.idnum;
            salary=emp.salary;
        }

        void show()
        {
            cout<<"2nd emp:"<<endl<<"idnum="<<idnum<<endl<<"salary="<<salary<<endl;
        }
};

main()
{
    int a;
    double b;

    cout<<"enter id num and salary"<<endl;
    cin>>a>>b;
    employee e1(a,b);
    e1.dis();
    employee e2;
    e2=e1;
    e2.show();  
}

【讨论】:

    【解决方案2】:

    这可能会有所帮助:

    // Operator overloading in C++
    //assignment operator overloading
    #include<iostream>
    using namespace std;
    
    class Employee
    {
    private:
    int idNum;
    double salary;
    public:
    Employee ( ) {
        idNum = 0, salary = 0.0;
    }
    
    void setValues (int a, int b);
    void operator= (Employee &emp );
    
    };
    
    void Employee::setValues ( int idN , int sal )
    {
    
    salary = sal; idNum = idN;
    
    }
    
    void Employee::operator = (Employee &emp)  // Assignment operator overloading function
    {
    salary = emp.salary;
    }
    
    int main ( )
    {
    
    Employee emp1;
    emp1.setValues(10,33);
    Employee emp2;
    emp2 = emp1; // emp2 is calling object using assignment operator
    
    }
    

    【讨论】:

    • 如果你能解释一下贴出的sn-p代码中的关键区域,那将比仅仅发布一个sn-p代码更有帮助。
    【解决方案3】:

    第二个很标准。您通常更喜欢从赋值运算符返回引用,以便像 a = b = c; 这样的语句按预期解析。我想不出任何我想从作业中返回副本的情况。

    需要注意的一点是,如果您不需要深度复制,有时认为最好使用编译器生成的隐式复制构造函数和赋值运算符,而不是自己滚动。不过真的取决于你...

    编辑:

    以下是一些基本调用:

    SimpleCircle x; // default constructor
    SimpleCircle y(x); // copy constructor
    x = y; // assignment operator
    

    现在说我们有你的赋值运算符的第一个版本:

    SimpleCircle SimpleCircle::operator=(const SimpleCircle & rhs)
    {
         if(this == &rhs)
            return *this; // calls copy constructor SimpleCircle(*this)
         itsRadius = rhs.getRadius(); // copy member
         return *this; // calls copy constructor
    }
    

    它调用复制构造函数并传递对this 的引用以构造要返回的副本。现在在第二个示例中,我们通过返回对 this 的引用来避免复制

    SimpleCircle & SimpleCircle::operator=(const SimpleCircle & rhs)
    {
        if(this == &rhs)
           return *this; // return reference to this (no copy)
        itsRadius = rhs.getRadius(); // copy member
        return *this; // return reference to this (no copy)
    }
    

    【讨论】:

    • 其实我想确定这个拷贝构造函数在哪里被调用。我正在使用 cout
    • 我指的是在您的第一个示例中按值返回副本。
    【解决方案4】:

    赋值运算符的第二个版本没有问题。事实上,这是赋值运算符的标准方式。

    编辑:请注意,我指的是赋值运算符的返回类型,而不是实现本身。正如在 cmets 中所指出的,实现本身是另一个问题。见here

    【讨论】:

    • 其实标准的方法是Copy & Swap 方法不是上面提到的。
    • @Als:当您需要处理远程所有权时,复制和交换当然是标准的。当处理一个单一的、简单的值时,我会称之为矫枉过正(尽管仍然可能比问题中的要好)。
    • @JerryCoffin:实际上,我确实提倡复制和交换单值调用,因为一旦你学会了正确的方法,就很难搞砸复制和交换。
    • @Als 我指的是通过引用返回,而不是实现。我会澄清这一点。
    • @Als:我通常提倡的是,如果它只包含简单的值,那么默认实现将正常工作(并且应该正常使用)。
    【解决方案5】:

    这是使用运算符重载的正确方法 现在你通过引用得到你的对象 避免价值复制。

    【讨论】:

      【解决方案6】:

      在这种情况下,您几乎肯定最好跳过检查自分配 - 当您只分配一个似乎是简单类型(可能是双精度)的成员时,这样做通常更快分配而不是避免它,所以你最终会得到:

      SimpleCircle & SimpleCircle::operator=(const SimpleCircle & rhs)
      {
          itsRadius = rhs.getRadius(); // or just `itsRadius = rhs.itsRadius;`
          return *this;
      }
      

      我意识到许多较旧和/或质量较低的书籍都建议检查自我分配。然而,至少根据我的经验,没有它会更好的情况非常罕见(如果操作员依赖它来确保正确性,那么它几乎肯定不是异常安全的)。

      顺便说一句,我要注意,要定义一个圆,您通常需要一个圆心和一个半径,当您复制或分配时,您希望同时复制/分配两者。

      【讨论】:

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