【问题标题】:Which is a better Get member method?哪个是更好的获取成员方法?
【发布时间】:2013-12-19 21:08:36
【问题描述】:

我有一个类的成员类型为std:vector

  private:
     std::vector<int> myVector;

我已经创建了 Get 方法来访问myVector

1. const std::vector<int>   GetMyVector() const;
2. const void   GetMyVector(std::vector<int>& vec) const;

分别实现如下:

1. const std::vector<int> MyClass::GetMyVector() const
   {
       return  myVector;
   }

2. const void MyClass::GetMyVector(std::vector<int>& vec) const
   {
       vec =  myVector;
   }

两种 Get 方法中哪一种更好,为什么?

【问题讨论】:

  • 第一个选项复制向量,这不是get的思想。第二个选项允许在函数调用后对 myVector 进行写访问...
  • 您希望调用者拥有自己的向量副本,还是希望他们有权访问数据成员?
  • @juanchopanza 目的只是为了访问会员。无意复制。
  • 好的,你的方法都没有这样做,所以它们都很差。
  • @juanchopanza 我应该和 simonc 一起去

标签: c++ class vector stdvector accessor


【解决方案1】:

我更喜欢选项 3:

const std::vector<int>& MyClass::GetMyVector() const
{
    return  myVector;
}

您的选项 1 返回了myVector 的副本。这将返回对类成员的 const(只读)引用。

【讨论】:

  • 也许他们想要返回一份副本。
  • @simonc 我在某处读到,如果函数的返回是一个聚合,它应该是通过引用输出参数而不是通过返回。这是真的吗?
  • @ontherocks 不,这不是真的。
  • @juanchopanza 是的,但在这种情况下我会发现函数名称有点误导。想要副本的客户不能通过std::vector&lt;int&gt; copy(myClass-&gt;GetMyVector()); 处理这个吗?
  • @EmilioGaravaglia 当然有不同级别的封装(假设引用是数据成员)。引用和值是完全不同的东西。调用者无法通过引用修改数据这一事实并不会改变他们对可能改变甚至消失的事物的引用这一事实。
【解决方案2】:

为什么要返回向量?

int MyClass::GetItem(const size_t index) const
{
    return myVector[index];
}

【讨论】:

  • 避免添加GetSizeBeginEnd等。得墨忒耳法则有时会改善事情,有时会使事情变得更糟。
  • @SteveJessop 当然,这完全取决于向量的用途。
【解决方案3】:

根据经验,总是尝试返回类成员的const reference。 所以使用const std::vector&lt;int&gt; &amp; MyClass::GetMyVector() const

【讨论】:

    【解决方案4】:

    如果您通过复制返回一个对象,那么将其声明为 const 是没有任何意义的。所以不是

    const std::vector<int> MyClass::GetMyVector() const
    {
        return  myVector;
    }
    

    我会写

    std::vector<int> MyClass::GetMyVector() const
    {
        return  myVector;
    }
    

    第二个声明比第一个更糟糕,因为它只会让用户感到困惑。不清楚是类的对应数据成员赋值给了参数,还是这个方法对参数做了一些改动,没有给参数赋值对应的数据成员。

    所以考虑到您建议的变体,我会选择声明

    std::vector<int> MyClass::GetMyVector() const
    {
        return  myVector;
    }
    

    【讨论】:

      【解决方案5】:

      首先,当您从成员函数返回类的私有成员时,您会暴露您的实现,这通常是糟糕的设计。查看@JoachimPileborg 的解决方案,了解如何避免这种情况的示例。

      如果你想返回一个副本,那么你应该按值返回。

      如果要返回对对象的引用,则按引用返回。 但是,请记住,当对象被破坏时,您最终会得到一个悬空引用,例如

      class Foo {
      public:
          std::vector<int>& getVec() {
              return myVec;
          }
      private:
          std::vector<int> myVec;
      };
      
      int main() {
          Foo* f = new Foo();
          std::vector<int>& myRef = f->getVec();
          delete f;
      
          std::cout << myRef.size(); // The demons come! Dangling reference!
      }
      

      因此,返回副本而不是引用通常是正确的做法。

      【讨论】:

      • ...“这通常是糟糕的设计”...这只是一种偏见。这里根本没有足够的上下文来说明整体设计。
      • @EmilioGaravaglia 我不同意,设计原则是一种很好的做法,尤其是当您没有足够的经验来预见以后的问题时。设计原则旨在应用于有限的环境,因此您可以抽象您的整体设计。在这种情况下,公开实现会创建一个严格的设计,因为对类的更改(例如容器类型的更改)将需要对使用该函数的每个其他类进行更改。
      • 每一个设计都可能对某些东西有好处,也可能对其他东西不好。设计原则不在信息论物理学之外。有许多“模式”,也有许多“反模式”。一种反模式是“过度工程”:即使上下文不需要它,它也会在强制遵循原则时发生。我们谁也无法评估完全缺失的上下文信息。
      • @EmilioGaravaglia 当我们谈论面向对象编程并且类不是聚合时,暴露类的私有成员是一种反模式的指示。回应是:你不应该这样做。我认为由于缺乏上下文而将其称为“过度工程”是您自己的经验造成的夸大其词,这不一定是给初学者的最佳建议。我之前的评论仍然适用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-10-30
      • 2017-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-07
      • 2020-01-29
      相关资源
      最近更新 更多