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

C++ 哪种方法更适合实现get/set?,c++,get,set,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; }; 注意:在这种方法中,

实现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;
};
注意:在这种方法中,get足够快:

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

定义两个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;
};
使用以下方法:

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

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

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

void set_data(my_class value)
{
  m_data = value;
}
你可能应该通过引用来传递

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

至于应该选择哪种方法,请这样想——在第二种方法中,返回对内部对象的引用,用户完全可以自由地使用它。使用第一种方法,您可以控制用户可以做什么或不能做什么

任何自定义类都应始终使用引用来传递地址,而不是值类。还应避免传回非常量引用进行编辑。我的建议见下文

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

第二种方法看起来非常笨拙。

通常定义getter/setter:

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

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

<> P>我知道这不是一个流行的答案,在我学习Python之前,C++露比是不可能的。但是既然您提供的getter和setter不进行范围检查或特殊计算,为什么不公开成员

 class main_class
 {
  public:
    my_class my_data;
 }

当然,您将丢失getter上的
const
,并且不能保证得到保护,但是您也不能保证得到保护,因为您提供了一个set函数,它修改了成员

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

虽然像方法1这样的标准getter和setter可以提供“封装”,除非这些函数内联在头中,否则它们会增加很多开销。例如,在紧密循环中,即使使用引用而不是按值传递(这需要昂贵的内存复制操作),每次调用getter/setter都要在x86中不断添加大约8条指令,以便在堆栈上设置其激活记录以及函数的序言和尾声,这会占用宝贵的CPU时间,并且会严重影响性能。因为你是一个能手,二传手做的不多,所以你真的不需要他们


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

我觉得第一个方法是干净且易于理解的。我会选择第一种方法。这两种方法都不是好的解决方案。第一种方法对类使用值类型而不是引用,第二种方法返回一个非常量引用进行编辑,这不好。请看下面我的答案。为什么不使用公共变量?封装?这是一个过于简单的示例,getter/setter方法实际上是在执行验证还是其他功能?有很多不使用公共变量的理由。@Amir:我认为你没有完全理解你链接的文章。您编写的setter不属于本文所写的内容,对于getter,它将取决于其他设计约束,但无论用户代码做什么,您都在强制复制(考虑
std::cout Value更好。当出现右值引用时,第二个表单将在可能是移动时调用副本,这既低效又可能不正确,具体取决于类型。此外,此类值副本是编译器RVO/NRVO的主要目标,通常不需要人工优化器。但是,它定义了可以通过使用swap()来改进。这将是一个很好的复制和交换。@DeadMG:除非您使用的是C++0x(在这种情况下,您将使用右值引用)这种特殊情况下的替代方案是:通过引用传递并在内部进行复制,通过值传递并交换可交换的对象。我必须同意Armen的观点:没有必要仅仅因为代码在编写过程中速度很快,而在重写之后,就让代码对当前编译器有害!同样,这段代码声明提出问题的人不理解链接的文章。+1,总的来说,真正的选择要么是选项一,使用setter进行参数设置并允许您执行检查,要么只是将成员公开。只编写两个方法将其转换为公共。大卫,很高兴你同意。我花了一段时间重新思考了我在大学里学过的必修课。你至少忘记了一种方法