23

(撇开你是否应该拥有它们的问题。)

我一直喜欢只使用函数重载来为 getter 和 setter 提供相同的名称。

int rate() { return _rate; }      
void rate(int value) { _rate = value; }

// instead of     
int getRate() { return _rate; }      
void setRate(int value) { _rate = value; }

// mainly because it allows me to write the much cleaner     
total( period() * rate() );    
// instead of      
setTotal( getPeriod() * getRate() );

当然我是对的,但我想知道图书馆作者是否有充分的理由?

4

13 回答 13

33

我更喜欢 get/set 版本,因为它更清楚发生了什么。如果我看到 rate() 和 rate(10),我怎么知道 rate(10) 不是简单地在计算中使用 10 来返回速率?我没有,所以现在我必须开始搜索以弄清楚发生了什么。一个函数名应该做一件事,而不是两件相反的事情。

此外,正如其他人指出的那样,有些人更喜欢省略“get”并离开“set”,即

int Rate( );
void SetRate( int value );

该约定也很清楚,我阅读它不会有任何问题。

于 2009-10-22T21:25:55.443 回答
6

我一直喜欢在我的吸气剂上省略“get”,就像你做的那样,rate()而不是getRate(). 但是对我来说,重载设置器似乎不是一个好主意,因为名称rate并没有传达出对象正在发生变异。考虑:

total(period() * rate()); // awesome, very clear

rate(20); // Looks like it computes a rate, using '20'...but for what?  And why ignore the return value?
于 2009-10-22T21:28:33.137 回答
6

int rate();和怎么样void setRate(int value);?这样做的好处是没有两个同名的函数做不同的事情,并且仍然允许period() * rate().

于 2009-10-22T21:29:19.193 回答
5

几年前,我会完全同意。最近,一个疑问开始出现,因为这使得获取 getter 或 setter 的地址变得模棱两可。使用 tr1::bind 之类的工具,这真的很烦人。

例如:

struct A
{
   void Foo(int);
   int Foo()const;
};

std::vector<A> v = ....;
std::vector<int> foos;
// Extract Foo
std::transform(
   v.begin(), v.end(), 
   std::back_inserter(foos), 
   //Ambiguous
   // std::tr1::bind(&A::Foo)
   //must write this instead. Yuck!
   std::tr1::bind(static_cast<int(Foo::*)()>(&A::Foo));
);

撇开你是否应该拥有它们的问题不谈;-)

于 2009-10-22T21:30:04.663 回答
4

我会继续提到这应该是一个社区维基问题。

当我开始学习 C++ 时,我寻找了风格指南,而谷歌的在某些方面很有用:

  • 大写的方法(它更漂亮)。
  • getter 简单且小写 ( rate)。
  • 显式设置器和小写 ( setRate)。
于 2009-10-22T21:31:38.223 回答
2

简洁很重要,但不能以不完整或误导为代价。出于这个原因,我更喜欢 GetFoo() 和 SetFoo() 而不是 Foo() 和 Foo(int foo)。

于 2009-10-22T21:34:17.563 回答
2

“获取”和“设置”有几个级别

  • 我使用 Get 和 Set 进行“快速”操作。
  • 如果某些事情需要更长的时间来执行,那么它通常是一个 Calc,因为这些名称意味着必须做一些工作来检索结果。
  • 对于更长的操作,您开始使用加载/保存、查询/存储、读/写、搜索/查找等前缀。

因此,Get/Set 可以被赋予有用的含义,并成为更大、一致的命名策略的一部分。

于 2009-10-22T21:43:25.340 回答
2

另一个没有人提到的问题是函数重载的情况。以这个(人为且不完整的)示例为例:

class Employee {
    virtual int salary() { return salary_; }
    virtual void salary(int newSalary) { salary_ = newSalary; }
};

class Contractor : public Employee {
    virtual void salary(int newSalary) {
        validateSalaryCap(newSalary);
        Employee::salary(newSalary);
    }
    using Employee::salary; // Most developers will forget this
};

如果没有该using子句,用户将Contractor无法查询薪水,因为过载。我最近添加-Woverloaded-virtual到我从事的一个项目的警告集中,你瞧,这到处都是。

于 2009-10-23T01:21:57.110 回答
1

虽然 Ed 的评论是正确的,但我确实更喜欢实际属性而不是 setter/getter 反模式。当域图中 1/3 的方法是由 eclipse 生成的虚拟方法时,就会出现问题。

然而,如果没有一流的属性,我相信反模式是最有意义的。

此外,它使代码完成更容易。

obj.set (control shift space)用于设置器
obj.get (control shift space)用于获取器

于 2009-10-22T21:28:03.653 回答
1

就个人而言,我认为成对出现的 getter 和 setter 是从“视觉”语言及其“属性”中遗留下来的代码气味。在“好”类中,数据成员是只写或只读的,但不是读/写的。

我认为 getter 和 setter 最常见的原因是对象模型的深度不够。在您的示例中,为什么总要通过期间和费率?他们不是班上的成员吗?所以你应该只设置周期和利率,你应该只得到一个总数。

可能有例外,但我只是讨厌查看一个类并找到“getX/setX、getY/setY 等”。似乎对如何使用该类没有足够的想法,而是作者使该类易于获取数据,因此他不必考虑应如何使用该类。

自然我是对的。

于 2009-10-22T21:36:43.500 回答
0

我强制执行约定,其中方法应始终是动词,类应始终是名词(出于显而易见的原因,函子除外)。在这种情况下,必须使用 get/set 前缀来保持一致性。也就是说,我也完全同意 Ed Swangren 的观点。这对我来说总结为使用这些前缀是不费吹灰之力的。

于 2009-10-22T22:40:49.573 回答
0

我更喜欢避免获取和设置标签,编译器不需要这些信息来完成大多数这些简单属性的工作。

你可能有问题:

class Stuff {
  void widget( int something ); // 'special' setter
  const Widget& widget( int somethingelse ) const; // getter
}
Stuff a; 
a.widget(1); // compiler won't know which widget you mean, not enough info
于 2009-10-23T03:47:59.873 回答
0

如果你的 getter 是简单rate()的,你的编译器会抱怨它重新定义了你的其他rate符号,只要你给你的字段一个像这样的好有意义的名字。在这种情况下,您需要做一些愚蠢的事情,例如为您的成员命名_rate或其他类似的方法。我个人讨厌看到/输入那些下划线,所以倾向于采用这种getRate()方法。

这显然是主观的,这恰好是我个人的偏好。

于 2017-03-24T04:46:06.607 回答