C ++中访问器方法(getter和setter)的约定

时间:2010-09-05 19:29:21

标签: c++ accessor setter getter

关于C ++中的访问器方法的几个问题已经被问到,但是没有一个能够满足我对这个问题的好奇心。

我尽可能地避免使用访问器,因为像Stroustrup和其他着名的程序员一样,我认为一个类很多都是OO的标志。在C ++中,我可以在大多数情况下为类添加更多的责任或使用friend关键字来避免它们。但在某些情况下,您确实需要访问特定的班级成员。

有几种可能性:

1。根本不要使用访问者

我们可以公开相应的成员变量。这在Java中是不行的,但对于C ++社区似乎没问题。但是,我有点担心的情况是显式副本或对象的只读(const)引用应该返回,是夸大了吗?

2。使用Java风格的get / set方法

我不确定它是否来自Java,但我的意思是:

int getAmount(); // Returns the amount
void setAmount(int amount); // Sets the amount

第3。使用客观的C风格获取/设置方法

这有点奇怪,但显然越来越普遍了:

int amount(); // Returns the amount
void amount(int amount); // Sets the amount

为了使其起作用,您必须为您的成员变量找到不同的名称。有些人附加下划线,其他人加上“m_”。我也不喜欢。

你使用哪种风格?为什么?

10 个答案:

答案 0 :(得分:38)

从我的角度来看,从维护的角度来看,有400万行C ++代码(这只是一个项目)我会说:

  • 如果成员是不可变的(即const)或没有依赖的简单(如带有成员X和Y的点类),则不使用getter / setter。

  • 如果成员是private,那么也可以跳过getter / setter。如果.cpp单位很小,我也会将内部pimpl - 类的成员计为private

  • 如果成员为public protected protectedpublic一样差)且非{{1然后,使用getters / setters,非简单或具有依赖关系。

作为维修人员,我想要拥有吸气剂/安装者的主要原因是因为我有一个地方可以放置断点/记录/其他东西。

我更喜欢替代方案2的风格,因为它更易于搜索(编写可维护代码的关键组件)。

答案 1 :(得分:7)

  1. 我从不使用这种风格。因为它可以限制你的类设计的未来,并且明确的geters或setter与一个好的编译器一样有效。

    当然,实际上内联显式getter或setter会在类实现上创建同样多的底层依赖。这只是减少语义依赖。如果更改它们,仍然需要重新编译所有内容。

  2. 当我使用访问器方法时,这是我的默认样式。

  3. 这种风格对我来说太“聪明”了。我确实在极少数情况下使用它,但仅限于我真的希望访问者尽可能多地感受变量。

  4. 我认为有一个简单的变量包可能是一个构造函数,以确保它们都被初始化为理智的东西。当我这样做时,我只需将其设为struct并将其全部公开。

答案 2 :(得分:7)

2)是最好的IMO,因为它使你的意图最清晰。 set_amount(10)amount(10)更有意义,因为一个好的副作用允许名为amount的成员。

公共变量通常是一个坏主意,因为没有封装。假设您需要在更新变量时更新缓存或刷新窗口?如果您的变量是公开的,那就太糟糕了。如果你有一个set方法,你可以在那里添加它。

答案 3 :(得分:6)

  1. 如果我们只想表示pure数据,这是一种很好的风格。

  2. 我不喜欢它:)因为当我们可以在C ++中重载它们时,get_/set_实际上是不必要的。

  3. STL使用此样式,例如std::streamString::strstd::ios_base::flags,除非应该避免!什么时候?当方法的名称与其他类型的名称冲突时,会使用get_/set_样式,例如std::string::get_allocator,因为std::allocator

答案 4 :(得分:4)

一般来说,我觉得系统中有太多实体使用过多的getter和setter并不是一个好主意。这只是一个糟糕的设计或错误的封装的迹象。

话虽如此,如果需要重构这样的设计,并且源代码可用,我宁愿使用访问者设计模式。原因是:

  

一个。它为班级提供了机会   决定允许谁访问它   私人州

     

湾它给了一个班级   有机会决定访问哪些内容   允许每个实体   对其私人州感兴趣

     

℃。它   明确记录这种外部访问   通过明确的类接口

基本理念是:

  

a)如果可能的话重新设计,

     

b)中   重构这样

     
      
  1. 所有对类状态的访问都是通过众所周知的 individualistic 进行的   接口

  2.   
  3. 应该可以配置某种做什么和不该做什么   对于每个这样的界面,例如所有   从外部实体访问 GOOD   应该被允许,所有访问权限   外部实体 BAD 应该是   不允许,外部实体确定   应该被允许但不能设置(例如)

  4.   

答案 5 :(得分:2)

  1. 我不会排除使用访问者。可能对某些POD结构而言,但我认为它们是好事(有些访问器也可能有其他逻辑)。

  2. 如果您的代码一致,那么命名约定并不重要。如果您使用多个第三方库,他们可能会使用不同的命名约定。所以这是一个品味问题。

答案 6 :(得分:1)

我已经看到了类的理想化而不是整数类型来引用有意义的数据。

下面这样的内容通常没有很好地利用C ++属性:

struct particle {
    float mass;
    float acceleration;
    float velocity;
} p;

为什么呢?因为p.mass * p.acceleration的结果是浮点而不是预期的力。

用于指定目的的类的定义(即使它是一个值,如前面提到的 amount )更有意义,并允许我们执行以下操作:

struct amount
{
    int value;

    amount() : value( 0 ) {}
    amount( int value0 ) : value( value0 ) {}
    operator int()& { return value; }
    operator int()const& { return value; }
    amount& operator = ( int const newvalue )
    {
        value = newvalue;
        return *this;
    }
};

您可以通过operator int隐式访问amount中的值。此外:

struct wage
{
    amount balance;

    operator amount()& { return balance; }
    operator amount()const& { return balance; }
    wage& operator = ( amount const&  newbalance )
    {
        balance = newbalance;
        return *this;
    }
};

Getter / Setter用法:

void wage_test()
{
    wage worker;
    (amount&)worker = 100; // if you like this, can remove = operator
    worker = amount(105);  // an alternative if the first one is too weird
    int value = (amount)worker; // getting amount is more clear
}

这是一种不同的方法,并不意味着它的好坏,而是不同的。

答案 7 :(得分:0)

另一种可能性是:

int& amount();

我不确定我会推荐它,但它的优点是不寻常的符号可以阻止用户修改数据。

str.length() = 5; // Ok string is a very bad example :)

有时它可能只是一个不错的选择:

image(point) = 255;  

另一种可能性,使用功能表示法来修改对象。

edit::change_amount(obj, val)

这样危险/编辑功能可以在一个单独的命名空间中用它自己的文档拉出来。这个似乎与通用编程自然而然。

答案 8 :(得分:0)

让我告诉你一个额外的可能性,这似乎是最明智的。

需要阅读&修改

简单地声明变量public:

class Worker {
public:
    int wage = 5000;
}

worker.wage = 8000;
cout << worker.wage << endl;

只需阅读

class Worker {
    int _wage = 5000;
public:
    inline int wage() {
        return _wage;
    }
}

worker.wage = 8000; // error !!
cout << worker.wage() << endl;

这种方法的缺点是,当您想要更改访问模式时,需要更改所有调用代码(添加括号)。

答案 9 :(得分:0)

第3种变化,有人告诉我这可能是“流利的”风格

class foo {
  private: int bar;
  private: int narf;
  public: foo & bar(int);
  public: int bar();
  public: foo & narf(int);
  public: int narf();
};

//multi set (get is as expected)
foo f; f.bar(2).narf(3);