【问题标题】:Reference Operator to a Return Value?返回值的引用运算符?
【发布时间】:2012-01-01 23:52:12
【问题描述】:

我正在学习 C++ 中的面向对象编程。我对以下代码有一些疑问:

class Vehicle 
{ 
  protected: 
    string license ; int year ;
  public:
    Vehicle(const string &myLicense, const int myYear) : license(myLicense), year(myYear){}

    const string getDesc() const 
    {
      return license + " from " + stringify(year);
    } 
    const string &getLicense() const {return license;} 
    const int getYear() const {return year;} 
};
  • 对函数的返回值使用引用运算符 (&) 是什么意思。为什么使用方便?我认为结果是完全一样的,无论你在getlicense函数中是否使用(&),你使用的内存量都是一样的。

  • 为什么这段代码使用保留字 const?我看到它可以使用它。在代码中使用 const 有什么好处吗?

提前感谢您的帮助。

【问题讨论】:

    标签: c++ object reference


    【解决方案1】:

    通过返回对许可证的引用,您可以保存会导致内存分配的复制操作。通过使其成为 const 引用,它可以防止调用者修改内部状态。

    【讨论】:

      【解决方案2】:

      当您有const string &getLicense() const {return license;} 时,表示您返回许可值通过引用。如果没有&,您将按值返回。 Quoting:

      当一个变量通过引用返回时,对该变量的引用被传回给调用者。然后调用者可以使用这个引用来继续修改变量,这有时很有用。通过引用返回也很快,这在返回结构和类时很有用。

      现在,如果没有const,调用者将能够修改您的license 成员值的值,并且根据您不希望发生这种情况的代码。

      所以,总而言之,& 用于按引用返回,这比按值返回要快(因为您只返回引用而不复制对象),而使用const为了禁止修改。


      您可以阅读有关按引用返回的更多信息here, on C++-FAQ-lite

      【讨论】:

        【解决方案3】:

        它用于在返回对象时避免不必要的复制,尽管它也取决于调用站点,因为在调用站点可以复制,也可以不复制:

        std::string copy = veh.getLicence(); //makes a copy
        const std::string & notAcopy = veh.getLicence(); //does not make a copy
        
        //and most importantly here
        size_t size = veh.getLicense().size(); //doesn't make a copy!
        

        返回引用特别有助于链式函数调用。在链式函数调用中,如果您不想在 copy 上调用函数,则必须通过引用返回,这样可以确保链式函数调用在 上原始 对象,就像上面的第三个示例一样。

        有些类的返回类型必须是 reference 类型(或 pointer 类型),否则它将无法工作,因为它们的复制构造函数已被禁用声明他们private。最常用的此类类是 IOStream 类,例如 std::istreamstd::ostream 以及从它们派生的所有类。在这种情况下,您必须使用std::ostream& 作为函数的返回类型(通常这些函数是operator<< 重载)。

        【讨论】:

          【解决方案4】:

          请更好地格式化您的代码!这是不必要的难以解析:

          class Vehicle 
          { 
          public:
            Vehicle(const string & myLicense, const int myYear)
              : license(myLicense)
              , year(myYear) 
            {}
          
            const string getDesc() const 
            {
              return license + " from " + stringify(year);
            } 
            const string & getLicense() const {return license;} 
            const int getYear() const {return year;} 
          protected:
            // good convention: put details that users shouldn't be paying attention to 
            // below the public parts that they *should* be paying attention to
            string license;
            int year;
          };
          

          返回 const string & 意味着您授予外部世界的只读 (const) 访问权限,以直接与此对象的许可证交互(通过引用)(因为 getLicense() 就是这样做的)。

          通常这是一种提高效率的选择。即您可以按价值(副本)返回许可证,但是您正在复制许可证的内容。这样,您只是提供直接访问权限,但规定它是只读的。

          返回的 const 表明它是只读的。 方法声明末尾的 const 意味着您声明此方法不会更改此对象的值。

          如果调用者有一个 Vehicle 的 const 实例,后者尤其重要。不允许调用者调用非常量方法,因为它们只有对其 Vehicle 实例的只读访问权限。

          【讨论】:

            【解决方案5】:

            正如其他人已经指出的那样,返回引用可以避免复制。然而,我觉得有必要指出,故事通常不止于此。

            首先,返回对本地对象的引用通常会导致问题。因此,当您返回引用时,您通常需要做以下两件事之一:

            1. 您正在返回对某个预先存在的对象的引用(例如,许多 iostream 运算符都传递了对 iostream 的引用,并返回对同一 iostream 的引用;同样,赋值运算符通常会return *this; )。
            2. 函数动态分配它返回的对象。然而,在这种情况下,返回指针比返回引用更为常见。

            我什至可以说,在大多数情况下,所涉及的缺乏复制(或至少从缺乏复制中获得的效率)是比主要的更多或副业您返回参考的原因。在 iostream 的情况下,您返回一个引用主要是因为 iostream 基本上是一种“身份”类型的对象——即,您不能复制或分配一个对象。您创建一个,使用对那个唯一对象的引用,完成后销毁它。

            当您传递对对象的引用时,主要意图通常是消除副本。但是,当您返回引用时,这种情况就很少发生了。

            我还注意到,很长一段时间以来,大多数编译器都实现了返回值优化和命名返回值优化 (RVO/NRVO)。这意味着在任何情况下,与返回引用相比,返回值通常不会损失任何效率(事实上,编译器会在内部将返回值的代码转换为 接收 一个引用,并直接写入父级的值)。

            底线:返回引用并不像最初看起来那么简单或明显。除了少数常规的情况(插入、提取和赋值运算符是最明显的)之外,您可能真的需要考虑并知道自己在做什么,而不仅仅是简单、明显的优化。

            【讨论】:

              猜你喜欢
              • 2019-09-22
              • 1970-01-01
              • 2013-05-26
              • 1970-01-01
              • 2020-07-09
              • 2017-07-09
              • 1970-01-01
              • 1970-01-01
              • 2011-08-05
              相关资源
              最近更新 更多