开发者

Which method is better for implementing get/set?

开发者 https://www.devze.com 2023-03-23 12:48 出处:网络
There are two methos for implementing get/set. Method 1: Define get and set separately. class my_class { // ...

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_c开发者_开发问答lass 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.    
}


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


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.


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.


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


Usually getters/setters are defined:

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

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


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.


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.


IMHO the second method looks very awkward.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号