C++ 哪种方法更适合实现 get/set?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6830079/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 20:44:15  来源:igfitidea点击:

Which method is better for implementing get/set?

c++getset

提问by Amir Saniyan

There are two methos for implementing get/set.

有两种实现 get/set 的方法。

Method 1:

方法一:

Define get and set separately.

分别定义 get 和 set。

class my_class
{
  // ...
};

class main_class
{
public:

  my_class get_data() const
  {
    return m_data;
  }

  void set_data(my_class value)
  {
    m_data = value;
  }

private:

  my_class m_data;
};

Note: In this method get is fast enough: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value

注意:在这种方法中获取足够快:http: //cpp-next.com/archive/2009/08/want-speed-pass-by-value

And another method is (Method 2):

另一种方法是(方法2):

Define two get bodies, First const and another non const.

定义两个 get 主体,第一个是常量,另一个是非常量。

class my_class
{
  // ...
};

class main_class
{
public:

  const my_class& get_data() const
  {
    return m_data;
  }

  my_class& get_data() // Works like set.
  {
    return m_data;
  }

private:

  my_class m_data;
};

Using these methods:

使用这些方法:

void main()
{
  main_class cls;

  // For method 1.
  my_class data;
  data = cls.get_data();
  cls.set_data(data);

  // For method 2.
  const my_class data1;
  my_class data2;
  data1 = cls.get_data();  // const get invoked.
  cls.get_data() = data2; // Like set beacuase non const get invoked.

}

My question which of these methods for implementing get/set is better?

我的问题是这些实现 get/set 的方法中哪一个更好?

Do you know a better method?

你知道更好的方法吗?



Edit: For answers that believe Method 1 is better, what do you say in below situation:

编辑:对于相信方法 1 更好的答案,您在以下情况下怎么说:

void main()
{
  main_class cls;

  // For method 1.
  cls.get_data().do_something_else(); // Not effictive for cls, because data losts.

  // For method 2.
  cls.get_data().do_something_else(); // Effictive for cls.    
}

采纳答案by Chris Snowden

You should always use a reference for any custom classes to pass just the address not the value class. You should also avoid passing back a non-const reference for editing. See below for my recommendations.

您应该始终使用任何自定义类的引用来传递地址而不是值类。您还应该避免传递回非常量引用进行编辑。请参阅下面的我的建议。

class my_class
{
  // ...
};

class main_class
{
public:

  const my_class & get_data() const
  {
    return m_data;
  }

  void set_data(const my_class & data)
  {
    m_data = data;
  }

private:

  my_class m_data;
};

回答by nathan

I know this won't be a popular answer with C++ purists and before I learned Python, and Ruby I wouldn't have broached the possibility... but... Since the getter and setter you provided doesn't do range checking or special calculations why not make the member public?

我知道这不会是 C++ 纯粹主义者的流行答案,在我学习 Python 和 Ruby 之前,我不会提出这种可能性......但是......因为你提供的 getter 和 setter 不进行范围检查或特殊计算为什么不公开成员?

 class main_class
 {
  public:
    my_class my_data;
 }

Sure, you'll lose the conston the getter and won't be guaranteed protection, but you're not guaranteed that anyway because you provide a set function, which modifies the member.

当然,您将丢失constgetter 并且不能保证得到保护,但无论如何都不能保证,因为您提供了一个修改成员的 set 函数。

回答by unkulunkulu

The second one is very bad as it abandons the encapsulation: you can as well just make the corresponding field public, anyone could access it without your object knowing about it. You cannot perform range checks or status updates based on the data being changed etc.

第二个非常糟糕,因为它放弃了封装:您也可以将相应的字段设为公开,任何人都可以在您的对象不知道的情况下访问它。您无法根据正在更改的数据等执行范围检查或状态更新。

回答by Paul Manta

The second one would be a pretty bad choice. The reason for having setters is to be able to control how the member variable is modified by the user. If you just give the user a reference to your member, you lose all control.

第二个将是一个非常糟糕的选择。使用 setter 的原因是能够控制用户如何修改成员变量。如果你只是给用户一个对你的成员的引用,你就失去了所有控制权。

So you're pretty much left with the first method. Below are two variations that you might or might not like:

所以你几乎只剩下第一种方法了。以下是您可能喜欢或不喜欢的两种变体:

// First Variation
// ---------------
// In this one both the setter and the getter have the same name
// (which is the same as the member they control). To get a
// variable you do `int i = foo.var()` and to set it you do
// `foo.var(6)`. 

class Some
{
  public:
    int var() const {
        return var_;
    }

    void var(int v) {
        var_ = v;
    }

  private:
    int var_;
};

// Second Variation
// ----------------
// You can also make the setter return a reference to `this`.
// This allows you to chain setters, which can _sometimes_ be
// more readable but it also has a few disadvantages.

class Employee
{
  public:
    Employee& salary(double dollars) {
        salary_ = dollars;
        return *this;
    }

    Employee& name(const string& n) {
        name_ = n;
        return *this;
    }

  private:
    double salary_;
    std::string name_;
};

// You can now do this...
Employee emp;
emp.name("John Barlick").salary(500.00);

// ... But this can become quite ugly if you chain a large amount
// of setters (you'd then probably have to break the lines in
// order to keep the code readable). It also is (technically)
// less efficient. 

// In case you have lots of setters you could probably do this:
// emp.name("John Barlick")
//    .salary(500.00)
//    .some(787);
//    .another('g');  

回答by Vincent Mimoun-Prat

Usually getters/setters are defined:

通常定义 getter/setter:

  const my_class& get_data() const
  {
    return m_data;
  }

  void set_data(const my_class& _data)
  {
    m_data = _data;
  }

回答by Jason

While standard getters and settters like method 1 may provide "encapsulation", unless these functions are inlined in a header, they are adding a lot of overhead. For instance, in a tight loop, even if you used references rather than pass-by-value (which then requires a costly memory copy operation), constantly having to add about eight instructions in x86 for every call to a getter/setter in order to setup up its activation record on the stack as well as the function's prologue and epilogue is using up valuable CPU time, and really hurts performance. Since you're getter and setters aren't doing much, you really don't need them.

虽然像方法 1 这样的标准 getter 和 setter 可能会提供“封装”,除非这些函数被内联在头文件中,否则它们会增加很多开销。例如,在一个紧密的循环中,即使您使用引用而不是值传递(这需要昂贵的内存复制操作),每次调用 getter/setter 时都必须不断地在 x86 中添加大约 8 条指令在堆栈上设置其活动记录以及函数的序言和结尾会占用宝贵的 CPU 时间,并且确实会损害性能。由于您是 getter 和 setter 并没有做太多事情,因此您真的不需要它们。

Method 2 is actually what a number of STL containers do, like std::vectorwith the operator[], where you overload the same function, but define one for constant operations, and another for non-constant operations ... but again, you're adding unnecessary overhead when you could just publicly access the data member (i.e., it's not like you're some underlying pointers and other memory-managed data-members from us like an STL container). If the function you're passing it to requires a constant reference, it's not going to change the member anyways, so there's really no need to create an interface like this unless you are trying to make a common interface for accessing a member across a host of classes. And if you're doing that, then you should look into a pure virtual base class to define the common interface.

方法2其实就是一些STL容器的事,就像std::vectoroperator[],在那里你重载相同的功能,但定义了一个恒定的操作,另一个用于非恒定的操作......但同样,你当添加不必要的开销您可以只公开访问数据成员(即,您不像 STL 容器那样是我们的一些底层指针和其他内存管理数据成员)。如果你传递给它的函数需要一个常量引用,它无论如何都不会改变成员,所以真的没有必要创建这样的接口,除非你试图创建一个通用接口来访问一个成员跨主机类。如果你这样做,那么你应该研究一个纯虚拟基类来定义公共接口。

回答by Armen Tsirunyan

First of all, I think this is not very effective

首先,我认为这不是很有效

void set_data(my_class value)
{
  m_data = value;
}

You should probably pass by reference

您可能应该通过引用传递

void set_data(const my_class& value)
{
  m_data = value;
}

As to which method you should choose, think this way - In your second method you return a reference to your internal object and the user is absolutely free to do anything with it. With the first method, you can control what the user can or cannot do.

至于您应该选择哪种方法,请以这种方式思考 - 在您的第二种方法中,您返回对内部对象的引用,用户可以完全自由地对其进行任何操作。使用第一种方法,您可以控制用户可以做什么或不可以做什么。

回答by duedl0r

IMHO the second method looks very awkward.

恕我直言,第二种方法看起来很尴尬。