【问题标题】:Passing an Object by reference to Overloaded Operator - C++通过引用重载运算符传递对象 - C++
【发布时间】:2014-10-08 07:35:55
【问题描述】:

对 C++ 很陌生。我见过人们通常在运算符重载中通过引用传递对象。嗯,我不知道什么时候真的有必要。如下面的代码所示,如​​果我在 operator+ 中删除对象 c1 和 c2 声明中的 & 符号,我仍然会得到相同的结果。当我们不想修改 c1 或 c2 时,在这种情况下是否有任何理由通过引用传递?

#include <iostream>

class Keys
{
private:
    int m_nKeys;

public:
    Keys(int nKeys) { m_nKeys = nKeys; }

    friend Keys operator+(const Keys &c1, const Keys &c2);

    int GetKeys() { return m_nKeys; }
};


Keys operator+(const Keys &c1, const Keys &c2)
{
    return Keys(c1.m_nKeys + c2.m_nKeys);
}

int main()
{
    Keys cKeys1(6);
    Keys cKeys2(8);
    Keys cKeysSum = cKeys1 + cKeys2;
    std::cout << "There are " << cKeysSum.GetKeys() << " Keys." << std::endl;
    system("PAUSE");
    return 0;
}

【问题讨论】:

  • 如果不通过引用(或通过指针)作为参数传递对象,则通过值传递它们,这意味着它们被复制;有些对象的复制成本很高。
  • 好吧,如果您使用引用,则无需将对象作为参数复制为一件事,因此将参数作为引用可能会更有效

标签: c++ operator-overloading pass-by-reference


【解决方案1】:

运算符就像普通函数一样,只是有“花哨”的名字:)
(例如 operator+() 而不是 sum()

因此,您应用于函数的相同参数传递规则也可以应用于重载运算符。

特别是,当您有一个不便宜要复制的参数时(例如,intfloat便宜 复制参数的示例; 一个std::vector,一个std::string,是廉价复制参数的例子),你在你的方法中观察这个参数(即它是一个输入只读参数),那么你可以通过const引用传递它 (const &amp;)

这样,基本上就像将原始参数的地址传递给函数,所以不涉及深拷贝。深拷贝可能非常昂贵,例如想象一个包含大量元素的向量。

所以,回顾一下,你通过 const 引用 当:

  1. 参数只是不便宜复制(例如对于整数、浮点数等。只是 不要打扰:按值传递就可以了)
  2. 参数在函数/运算符实现中观察 (即它是一个输入只读参数)

【讨论】:

  • @Mr.C64 现在在ostream&amp; operator&lt;&lt; (ostream &amp;out, Something) { out &lt;&lt; Something &lt;&lt; endl; return out; } ostream 之后的 & 有什么作用?
  • @Farzin:使用&amp; 是因为out可修改 参数,它不是 只读输入参数。基本上,out 是对您附加自己的文本的流的引用。这个操作修改流对象,所以你不能通过const引用传递它,你必须去掉const。
  • @Mr.C64:我的意思是ostream&amp; operator中的&amp;
  • @Farzin:你的意思是在返回值中?那是因为您正在返回作为输入传递的 相同的 ostream。如果您按值返回(即 ostream 没有 &amp;),那么它将是副本不是原始输入的
  • 谢谢你!您的“便宜”术语更容易理解为什么应该通过引用。
【解决方案2】:

引用传递的优点:

  1. 它允许我们让函数更改参数的值,这有时很有用。
  2. 因为不复制参数,所以速度很快,即使与大型结构或类一起使用也是如此。
  3. 我们可以通过 const 引用传递以避免意外更改。
  4. 我们可以从一个函数返回多个值。

引用传递的缺点:

  1. 因为不能对文字或表达式进行非常量引用,所以引用参数必须是普通变量。
  2. 很难判断通过引用传递的参数是作为输入、输出还是两者兼而有之。
  3. 不可能从函数调用中看出参数可能会改变。按值传递和按引用传递的参数看起来是一样的。我们只能通过查看函数声明来判断参数是按值传递还是按引用传递。这可能会导致程序员没有意识到函数会改变参数的值。
  4. 因为引用通常由 C++ 使用指针实现,并且取消引用指针比直接访问它要慢,所以访问通过引用传递的值比访问通过值传递的值要慢。

您可以阅读以下内容:

http://www.cs.fsu.edu/~myers/c++/notes/references.html

【讨论】:

    【解决方案3】:

    如果您通过引用传递,则不会复制对象,这对于更复杂的类可以大大提高性能。

    在这种情况下,性能成本可能是微不足道的,并且可以想象编译器可以将其全部优化,但仍然值得这样做。稍后 Keys 类可能会变成更复杂的东西。

    【讨论】:

      【解决方案4】:

      考虑long 中的vector,其中有1000 万个条目。如果您对函数进行原型设计,例如:

      void foo(vector<long> vl)
      {
      }
      

      这将导致vector&lt;long&gt; 的赋值运算符(或复制构造函数) - 这将需要复制所有这些 10m 元素。稍后此临时对象 (vl) 的析构函数将取消分配内存并执行其他清理。它肯定会影响性能

      有一些类,特别是围绕同步提供程序(关键部分等),以及一些防止复制构造函数和/或赋值运算符的智能指针类 - 因此赋值或对象创建不会' t发生错误。虽然可以实现移动构造函数或移动赋值运算符。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-11
        • 2012-09-05
        • 2011-07-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多