【问题标题】:Assignment Operator Overload in c++c++中的赋值运算符重载
【发布时间】:2015-06-01 21:04:40
【问题描述】:

我意识到在网络上重载赋值运算符的例子之后有例子,但我花了最后几个小时试图在我的程序中实现它们并弄清楚它们是如何工作的,但我似乎做不到它和任何帮助将不胜感激。

我正在尝试实现一个重载的赋值运算符函数。

我有 3 个文件在工作,Complex.h 头文件、Complex.cpp 定义文件和我用作测试我的 Complex 类的驱动程序的 .cpp 文件。

在 Complex.h 头文件中我的赋值运算符原型:

Complex &operator= (Complex&);

到目前为止,我在 .cpp 文件中对重载运算符的定义是:

    Complex &Complex::operator=(Complex& first)
    {
         if (real == first.real && imaginary == first.imaginary)
             return Complex(real, imaginary);

         return first;
    };

我在函数中调用赋值运算符的方式是:

   x = y - z;

所以具体来说,我的问题是,当我用 x = y -z 调用重载赋值运算符时,当我返回传入的值时它不会将传入的值分配给 x,我无法弄清楚为什么从网络上的众多示例和解释中,任何帮助都将不胜感激,我提前感谢您的任何帮助。

【问题讨论】:

  • 您为什么不在一个接一个的例子中阅读其中的一些例子,并将您的赋值运算符建模为一个真正有效的?
  • = 不应该修改它的右手操作数。
  • @juanchopanza 我试过了,对此我深表歉意,并真诚地感谢您的意见,但我的大脑就是不能这样工作,我确实尝试阅读这些示例并在这些工作示例之后进行建模,但是它将以递归结束。
  • @zenith 所以你是说先返回我是在修改右手操作数?
  • 不,他显然没有修改右手操作数。

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


【解决方案1】:

重载的赋值运算符应该如下所示:

Complex &Complex::operator=(const Complex& rhs)
{
     real = rhs.real; 
     imaginary = rhs.imaginary;
     return *this;
};

您还应该注意,如果您重载赋值运算符,您应该以相同的方式重载 Complex 的复制构造函数:

Complex::Complex(const Complex& rhs)
{
    real = rhs.real; 
    imaginary = rhs.imaginary;
};

【讨论】:

  • 这是一个双重失败。首先,你超载了=,但让它做到了==,其次,自我分配是给过时的讲师,而不是在现实世界中使用
  • 我的等式运算符的代码在后面的代码中工作得很好,当我从赋值运算符函数返回值时,我需要能够修改左侧操作数(x)。
  • @DastardlyDeedDoer “当我从赋值运算符函数返回值时,我需要能够修改左边的操作数(x)。” 我的例子完全可以这个。
  • @Puppy 我完全同意,这是我在这里寻求帮助的主要原因,我所做的所有编码都没有做这样的废话。但这是针对我正在上的一门课,如果我不把它做好,我会得到很少的学分。但我使用相等运算符的主要原因是避免自赋值,除非我也走错了路。
  • @Puppy 有一个非常重要的用例,您只需拥有来检查自我分配:工作面试。 ;-)
【解决方案2】:

我认为您需要以下运算符定义

Complex & Complex::operator =( const Complex &first )
{
     real = first.real;
     imaginary = first.imaginary;

     return *this;
};

您必须返回对分配给的对象的引用。此外,参数应该是一个常量引用。在这种情况下,您可以将引用绑定到临时对象,或者您还必须编写移动赋值运算符。

在复制赋值运算符的实现中,您不会更改分配的对象。:) 您只需创建一个临时对象并返回对该临时对象的引用或返回对第一个对象的引用。

【讨论】:

  • 虽然严格准确,但这并没有太大帮助,因为它并没有真正向 OP 解释你为什么这样写。
  • 如果我正确理解了您的方法,我应该分配给真实和虚构的私有数据成员以创建一个新的 Complex 对象,然后返回创建的 Complex 对象以及当前(this)数据成员的地址?
  • @DastardlyDeedDoer 不,分配不应创建新对象(除非作为中间实现细节)。它分配一个值给现有的。
  • @juanchopanza 你是说我通过先返回来创建一个新对象?但是它不是已经创建了,因为我用它调用了重载运算符吗?所以我只是返回传入的值?还是我对这种方式的理解不对?
  • @DastardlyDeedDoer 不,我是说您不创建新对象,也不应该。我的意思是,您在损坏的代码中会这样做,但此答案中的代码不会。
【解决方案3】:

Assignment 接受两个对象,一个是要赋值的对象,另一个是具有所需值的对象。

作业应该:

  • 修改现有对象,该对象被分配给

作业不应:

  • 创建一个新对象
  • 修改具有所需值的对象。

假设我们正在处理的对象类型是:

struct S {
  int i;
  float f;
};

执行赋值的函数可能具有签名:

void assignment(S &left_hand_side, S const &right_hand_side);

它会被使用:

S a = {10, 32.0f};

S b;

assignment(b, a);

注意:

  • 左侧对象是可修改的,赋值会修改它,而不是创建一个新对象。
  • 右侧对象,即具有所需值的对象,不可修改。

此外,在 C++ 中,内置的赋值操作是表达式而不是语句;它有一个值,可以用作子表达式:

int j, k = 10;

printf("%d", (j = k));

这会将 j 设置为 k,然后获取该赋值的结果并将其打印出来。需要注意的重要一点是赋值表达式的结果是被赋值给的对象。没有创建新对象。在上面的代码中,j 的值被打印出来了(也就是 10,因为 j 刚刚从 k 分配了值 10)。

更新我们之前的分配函数以遵循此约定会产生如下签名:

S &assignment(S &left_hand_side, S const &right_hand_side);

实现如下:

S &assignment(S &left_hand_side, S const &right_hand_side) {
  // for each member of S, assign the value of that member in 
  // right_hand_side to that member in left_hand_side.
  left_hand_side.i = right_hand_side.i;
  left_hand_side.f = right_hand_side.f;

  // assignment returns the object that has been modified
  return left_hand_side;
}

注意这个赋值函数不是递归的;它不会在赋值中使用自己,但确实使用了成员类型的赋值

难题的最后一部分是让语法a = b 起作用,而不是assignment(a, b)。为此,您只需将assignment () 设为成员函数:

struct S {
  int i;
  float f;

  S &assignment(S &left_hand_side, S const &right_hand_side) {
    left_hand_side.i = right_hand_side.i;
    left_hand_side.f = right_hand_side.f;
    return left_hand_side
  }
};

left_hand_side 参数替换为*this

struct S {
  int i;
  float f;

  S &assignment(S const &right_hand_side) {
    this->i = right_hand_side.i;
    this->f = right_hand_side.f;
    return *this;
  }
};

并将函数重命名为operator=:

struct S {
  int i;
  float f;

  S &operator=(S const &right_hand_side) {
    this->i = right_hand_side.i;
    this->f = right_hand_side.f;
    return *this;
  }
};

int main() {
  S a, b = {10, 32.f};

  S &tmp = (a = b);

  assert(a.i == 10);
  assert(a.f == 32.f);

  assert(&tmp == &a);
}

另一件重要的事情是= 符号用在一个不是赋值的地方:

S a;
S b = a; // this is not assignment.

这是“复制初始化”。它不使用operator=。这不是任务。尽量不要混淆两者。

要记住的要点:

  • assignment 修改了被分配的对象
  • 赋值不会修改被赋值的对象。
  • 赋值不会创建新对象。
  • 赋值不是递归的,除非复合对象的赋值利用了它包含的所有小成员对象的赋值。
  • assignment 修改值后返回对象
  • 复制初始化看起来有点像赋值,但与赋值关系不大。

【讨论】:

  • 我知道这是不久前发布的 - 但它是一个非常周到的答案,应该保留。
猜你喜欢
  • 2013-03-30
  • 2016-08-30
  • 1970-01-01
  • 1970-01-01
  • 2012-04-22
  • 2011-01-27
  • 2011-05-31
  • 2012-08-17
  • 2018-12-27
相关资源
最近更新 更多