【问题标题】:What should a C++ getter returnC++ getter 应该返回什么
【发布时间】:2013-11-20 08:42:18
【问题描述】:

什么是 C++ getter 方法的最佳实践,它应该返回一个非平凡的类型,但是一个类型为 class 或 struct 的成员。

  1. 按值返回,如:MyType MyClass::getMyType() { return mMyType; }
  2. 通过 const 引用返回:const MyType& MyClass::getMyType() { return mMyType; }
  3. 按地址返回:MyType* MyClass::getMyType() { return &mMyType; }

在哪里

class MyType { /* ... */ };

class MyClass
{
  private:
     MyType mMyType;
}

我特别担心这种方法的以下用法。如果function() 想要保存它以供进一步使用,您能否详细说明这可能如何影响复制对象,以及悬空引用和野指针的危险。

MyType* savedPointer;

SomeType function(MyType* pointer) { savedPointer = pointer; };

一个。适用于 1. 和 2.

{
  MyType t = myClass.getMyType();
  function(&t);
}

// is savedPointer still valid here?

b.适用于 1. 和 2.

{
  const MyType& t = myClass.getMyType();
  function(&t);
}

// is savedPointer still valid here?

c。适用于 1. 和 2.

{
  MyType& t = myClass.getMyType();
  function(&t);
}

// is savedPointer still valid here?

d。有效期为 3。

{
  MyType* t = myClass.getMyType();
  function(t);
}

// is savedPointer still valid here?

其中myClassMyClass 类型的对象。

【问题讨论】:

  • 这在很大程度上取决于上下文。您想查看类内部的修改(例如修改向量元素)还是想明确地只拥有值,但从不(!)对原始值进行任何修改?在我看来,一般不应该使用指针。容器类型应按 ref 或 const ref 返回,其余按值返回(甚至根本没有 getter!)。类的重点是数据封装(以及其他功能)。总是通过非常量引用返回是愚蠢的。
  • 您还可以返回智能指针,让您省去很多烦恼...
  • @jbat100 您不能在此处返回智能指针。没有动态分配的对象(也不应该有)。
  • @JamesKanze 同意,要返回智能指针,实例变量必须是智能指针,这就是我的意思
  • @jbat100 但是为什么要让实例变量成为智能指针呢?

标签: c++ getter


【解决方案1】:

您可以提供 const 和非 const 版本:

MyType       & MyClass::getMyType()       { return mMyType; }
MyType const & MyClass::getMyType() const { return mMyType; }

我不会提供指针版本,因为这意味着返回值可能是空指针,在这种情况下它永远不可能。

然而,真正的一点是,您基本上是让调用者直接访问内部对象。如果这是您的意图,那么您不妨将数据成员公开。如果不是,那么您将需要更加努力地隐藏该对象。

一种选择是保留MyType const & 访问器,但提供更间接的方法来修改内部对象(setMyType(…) 或更适合您试图在包含类级别表达的语义)。

【讨论】:

  • @Simple:当然。我到了那里……
  • 这里需要注意的是,封装丢失了,因此有人可能会争辩说您不妨将成员公开。当然,getter 允许您稍后更改实现。
  • @Simple:并非不可能——您可能会开始返回对 MyClass 中数组中的多个对象之一的引用,或者动态分配的实例(可能按需创建),或者线程特定的实例等。
  • @Johan:有点。调用者可以在访问一次后缓存该值。
  • @Johan:缓存是不好的编码风格?
【解决方案2】:

一般来说,你应该更喜欢按值返回,除非你 明确希望保证参考将指定 一个成员(它暴露了你的部分实现,但是 在std::vector<>::operator[] 等情况下可取)。返回 引用可以防止以后类中的更改,因为这意味着 您无法返回计算值。 (这尤其 如果该类被设计为基类,则很重要,因为 返回引用会为所有派生创建此限制 类。)

您应该通过指针返回的唯一时间是查找或 涉及某些事情,这可能会在必须返回时返回 一个空指针。

返回对 const 的引用可能是一个有效的优化,如果 探查器在此处指示性能问题,并且调用 site 也可以处理 const 引用(不修改 返回值,对象的生命周期没有问题)。它 必须权衡额外的限制 实施,当然,但在某些情况下,这是合理的。

【讨论】:

    【解决方案3】:

    我总是会返回一个 const 引用。如果您需要修改它返回的值,只需使用 setter 函数。

    【讨论】:

    • 返回一个 const 引用对类的实现施加了很大的限制,并且至少部分违背了使用 getter 的目的。
    • 拥有getter的目的是访问存储的信息,而不是修改它。通过让 getter 函数返回一个 const 引用,您可以确保对象的状态只能通过 setter 进行修改。这为您提供了一些非常好的编译时间优化,并且更容易捕获一些错误。如果您认为您需要获取该项目的新副本,您始终可以显式使用复制构造函数(如果您返回且对象不是引用,则无论如何都会调用该复制构造函数)或者如果您需要修改大量的内部数据您可以提供帮助函数的对象。
    • 使用函数访问属性的目的不仅仅是让数据成员可见,而是不将代码锁定在特定的实现中。
    【解决方案4】:

    应避免按值返回,例如:MyType MyClass::getMyType() { return mMyType; },因为您将复制对象的内容。我看不到您可能获得的收益,但我看到了性能上的缺点。

    通过 const 引用返回:const MyType& MyClass::getMyType() { return mMyType; } 更普遍地使用这种方式:

    const MyType& MyClass::getMyType() const { return mMyType; }
    MyType& MyClass::getMyType() { return mMyType; }
    

    始终提供 const 版本。非常量版本是可选的,因为这意味着有人可以修改您的数据。这是我鼓励你使用的。

    按地址返回:MyType* MyClass::getMyType() { return &mMyType; } 主要用于数据可选存在的情况。使用前通常需要检查。

    现在,您的用例,我强烈建议不要将指针保存超过一个范围。我经常会导致所有权问题。我必须这样做,看看shared_ptr

    对于您的示例,有两种情况:

    一个。 savedPointer 在右大括号之后将不再有效。

    b、c 和 d。 savedPointer 在右大括号后有效,但请注意它不应超过 myClass

    【讨论】:

    • 通过 const 引用返回对类的实现有很大的限制,只有在分析器认为有必要时才应该使用;按值返回是默认值。
    • @JamesKanze 我不同意,有什么限制?按值返回总是会创建一个副本……这本身就是一个很大的限制。
    【解决方案5】:

    a) MyType t = 将为 1 和 2 创建对象的副本。一旦 t 超出范围,保存的指针将无效。

    b) 保存的指针对返回引用的情况有效,但对返回对象的情况无效。对于引用,指针的生命周期将与 myClass 相同。当然 const ref 上的 &t 将是 const t* 而不是 t* ,因此无法在您对 function(MyType*) 的调用中进行转换。

    c) 与 b 相同,但代码对 2 无效,因为您不能将 const MyType& 转换为 MyType&。通常这是不好的做法,而 const 形式会更容易接受。

    d) savedPointer 将与 myClass 具有相同的生命周期。

    我通常倾向于返回引用或 const 引用,具体取决于您希望能够对返回值做什么。如果您返回一个引用(非 const),您可以执行以下操作:myClass.getMyType() = ...,而如果您返回一个 const 引用,则该对象是只读的。

    【讨论】:

      猜你喜欢
      • 2012-12-04
      • 2010-09-17
      • 1970-01-01
      • 2021-08-12
      • 2019-01-14
      相关资源
      最近更新 更多