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

发布于 2024-11-26 06:00:00 字数 1515 浏览 2 评论 0原文

有两种方法可以实现 get/set。

方法一:

分别定义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;
};

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

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

定义两个get body,首先const和另一个非常量。

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;
};

使用这些方法:

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.

}

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

你知道更好的方法吗?


编辑: 对于认为方法 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.    
}

There are two methos for implementing get/set.

Method 1:

Define get and set separately.

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

And another method is (Method 2):

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

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?

Do you know a better method?


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

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.    
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

习ぎ惯性依靠 2024-12-03 06:00:00

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

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;
};

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;
};
很快妥协 2024-12-03 06:00:00

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

 class main_class
 {
  public:
    my_class my_data;
 }

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

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?

 class main_class
 {
  public:
    my_class my_data;
 }

Sure, you'll lose the const on 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.

简单 2024-12-03 06:00:00

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

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.

锦上情书 2024-12-03 06:00:00

第二个将是一个非常糟糕的选择。拥有setter的原因是能够控制用户如何修改成员变量。如果您只是向用户提供对您的会员的引用,您将失去所有控制权。

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

// 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');  

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.

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');  
一口甜 2024-12-03 06:00:00

通常 getter/setter 定义为:

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

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

Usually getters/setters are defined:

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

  void set_data(const my_class& _data)
  {
    m_data = _data;
  }
拒绝两难 2024-12-03 06:00:00

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

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

您可能应该通过引用传递

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

至于您应该选择哪种方法,请这样想 - 在您的第二种方法中,您返回对内部对象的引用,并且用户绝对可以自由地执行任何操作与它。使用第一种方法,您可以控制用户可以做什么或不能做什么。

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.

童话里做英雄 2024-12-03 06:00:00

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

方法 2 实际上是许多 STL 容器所做的事情,例如带有 operator[]std::vector,您可以重载相同的函数,但为常量操作定义一个函数,另一个用于非常量操作......但是,当您可以公开访问数据成员时,您会增加不必要的开销(即,它不像您是来自的一些底层指针和其他内存管理数据成员)我们就像一个STL容器)。如果您传递给它的函数需要一个常量引用,那么它无论如何都不会更改该成员,因此实际上没有必要创建这样的接口,除非您尝试创建一个通用接口来跨主机访问成员类。如果您这样做,那么您应该研究纯虚拟基类来定义公共接口。

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.

Method 2 is actually what a number of STL containers do, like std::vector with 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.

帅冕 2024-12-03 06:00:00

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

IMHO the second method looks very awkward.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文