【问题标题】:Operating overloading the assignment operator in c++在 C++ 中重载赋值运算符
【发布时间】:2012-08-17 07:48:47
【问题描述】:

我最近一直在制作分数类,重载运算符时没有得到预期的结果,我不知道为什么。希望有人可以帮助阐明一些光。我试图只包含相关代码。

const fraction fraction::operator* (fraction frac)
{
    return fraction(frac.numerator * numerator, frac.denominator * denominator);
}

const fraction fraction::operator* (int num)
{
    return fraction(numerator*num, denominator);
}

fraction& fraction::operator= (const fraction &rightSide)
{
    return *this;
}

这些操作是我发现可以正常工作的(其中 frac# 是一个分数对象):

frac1 = frac2;
frac3 = frac4 * 2;
frac5 = frac6 * frac7;

上述操作按预期工作,但以下操作使 frac8 保持初始化状态:

fraction frac8(4, 5); // Initializes a fraction, setting numerator = 4, denominator = 5
frac8 = frac8 * 3; // This doesn't quite work, leaving frac8 with the original numerator/denominator

我只是不明白为什么 frac3 = frac4 * 2 有效,但 frac8 = frac8 * 3 无效。有任何想法吗?在赋值运算符中使用 const 关键字我发现不是解决方案。

【问题讨论】:

  • 好吧,现在你的赋值运算符被定义为什么都不改变......你可能想要分配给一些成员变量。 :)

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


【解决方案1】:

如果在它的主体中你只做return *this;,你怎么期望你的operator= 做任何有用的事情?您必须将rightSide 的字段分配给this 的字段。

但是,更重要的是,如果您的类不管理需要在复制时进行特殊处理的资源,您可以使用编译器提供的赋值运算符。它只是将一个实例的字段复制到另一个实例中,对于 fraction 类来说,这似乎非常好。

顺便说一句,通常您使用复合运算符来实现“常规”运算符;你可能想看看operator overloading FAQ

【讨论】:

  • 感谢您的链接。我还没有完全意识到默认副本在这种情况下会起作用。无论如何,这主要是为了学习/练习。
【解决方案2】:

您的任何分配都不起作用,因为您的分配运算符实现是空的,除了返回对其左侧的引用之外什么都不做。

即这三个任务都没有

frac1 = frac2;
frac3 = frac4 * 2;
frac5 = frac6 * frac7;

确实有效。

出于某种原因,您声称上述作业“有效”,但这一定是您的某种困惑。他们不“工作”。出于同样的原因,frac8 = frac8 * 3 也没有。

P.S.我怀疑你的“工作”陈述实际上是这样写的

fraction frac1 = frac2;
fraction frac3 = frac4 * 2;
fraction frac5 = frac6 * frac7;

这可能确实有效。但是这种语法与赋值运算符无关。在这种情况下不使用赋值运算符。此语法对应于复制初始化。它依赖于类的复制构造函数(至少在概念上),而不是赋值运算符。这就是它可能起作用的原因,而真正的赋值不起作用,因为您通过将其设为空来“禁用”复制赋值运算符。

【讨论】:

  • 我相信他们在通过调用函数 toString() 方法并将其输出到控制台进行验证后工作。例如;我初始化了一个分数,比如 frac1,然后将 frac2 设置为 frac1。 frac2 假定 frac1 的属性,并且即使 frac1 以任何方式更改,它也保持应有的状态。所以说它不“工作”是令人费解的。它按给定示例中的预期工作。
  • @user1450120:这意味着您期望在左侧对象中看到的值以某种方式意外到达那里,而没有您的赋值运算符的任何帮助。这 [错误] 让您相信您的赋值运算符在某种程度上起作用,而实际上并非如此。
  • 有趣,我认为fraction frac3 = frac4 * 2;frac3 = frac4 * 2; 没有什么不同,谢谢您的信息。我确实确认在使用赋值运算符之前初始化 frac3 会给我带来不良影响。谢谢。
【解决方案3】:

您的赋值运算符仅返回对象本身(即*this)......所以在您的最后一个示例中,它只是一个空操作,而不是从右侧对象执行实际的赋值操作。换句话说,一个临时的fraction 对象是由您的operator* 创建的,但是由于您的赋值运算符不会复制右侧对象的值,因此您最终只是丢弃了由@ 生成的临时fraction 实例operator= 方法完成后的 987654326@。

顺便说一句,在创建用户生成的赋值运算符时,您可能需要查看rule-of-three。它基本上指出,如果您的类具有需要用户生成的赋值运算符的资源,那么您还应该实现用户定义的复制构造函数和析构函数......后两项的编译器生成的默认值不会如果需要管理的资源超出了编译器对这些方法的默认实现所实现的资源,就足够了。

【讨论】:

  • 我一定对 '*this' 的作用感到困惑。我认为它是右手边的对象。为什么'frac3 = frac4 * 2;'作品。鉴于您所说的,该语句似乎应该真正评估为“frac3 = frac4”。感谢您提供三规则链接。虽然这个类没有任何动态分配的东西,但我仍然只是在尝试学习/练习。
  • 你怎么知道它“有效”? frac4的初始值是多少,表达式完成后frac3的结果是什么?在您的示例代码中,似乎只有 frac8 以之前/之后的方式进行了测试,以注意到对象没有改变。
  • fraction frac8(6, 20);fraction frac9 = frac8 * 2;std::cout << "\nfrac8 = " << frac8.toStringS() << std::endl;std::cout << "frac9 = frac8 * 2\n" << "frac9 = " << frac9.toStringS() << std::endl;是我编译测试的一些代码。控制台的输出是:frac8 = 6 / 20 frac9 = frac8 * 2 frac9 = 12 / 20 给出的代码是严重精简的版本,仅用于表达我面临的问题。
  • 表达式fraction frac9 = frac8 * 2确实使用赋值运算符,而是使用复制构造函数,在这种情况下,它是编译器生成的默认复制构造函数。它使用复制构造函数的原因是因为该表达式是frac9 的第一个声明。如果你完成了fraction frac9;,然后frac9 = frac8 * 2;,你将调用你定义的赋值运算符,并最终得到frac9初始化的任何值,而不是复制frac8 * 2的值。
猜你喜欢
  • 2013-03-30
  • 2016-08-30
  • 1970-01-01
  • 1970-01-01
  • 2012-04-22
  • 2015-06-01
  • 2011-01-27
  • 2011-05-31
  • 2018-12-27
相关资源
最近更新 更多