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

时间:2011-07-26 12:35:13

标签: c++ get set

实现get / set有两种方法。

方法1:

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

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

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

定义两个get body,First const和另一个非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.    
}

8 个答案:

答案 0 :(得分:16)

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

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

答案 1 :(得分:11)

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

 class main_class
 {
  public:
    my_class my_data;
 }

当然,你将失去吸气剂上的const并且无法保证保护,但无论如何你都无法保证,因为你提供了一个修改成员的固定功能。

答案 2 :(得分:8)

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

答案 3 :(得分:4)

第二个将是一个非常糟糕的选择。拥有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');  

答案 4 :(得分:2)

通常定义getter / setter:

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

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

答案 5 :(得分:1)

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

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

您应该通过引用传递

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

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

答案 6 :(得分:1)

虽然方法1之类的标准getter和settter可能提供“封装”,但除非这些函数在标题中内联,否则它们会增加很多开销。例如,在紧密循环中,即使您使用引用而不是按值传递(这需要进行昂贵的内存复制操作),仍然需要在x86中为每次调用getter / setter按顺序添加大约8条指令在堆栈上设置激活记录以及函数的序言和结尾会占用宝贵的CPU时间,并且真的会损害性能。既然你是吸气鬼,而且制定者做得不多,你真的不需要它们。

方法2实际上是许多STL容器所做的事情,比如std::vectoroperator[],你重载相同的函数,但是为常量操作定义一个,为非常量操作定义另一个...但是,当你可以公开访问数据成员时,你会增加不必要的开销(也就是说,它不像你是一些底层指针和其他内存管理的数据成员,就像STL容器一样)。如果你传递给它的函数需要一个恒定的引用,它不会改变成员,所以除非你试图建立一个通用接口来访问主机上的成员,否则不需要创建这样的接口课程。如果你这样做,那么你应该研究一个纯虚拟基类来定义公共接口。

答案 7 :(得分:0)

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