关于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_”。我也不喜欢。
你使用哪种风格?为什么?
答案 0 :(得分:38)
从我的角度来看,从维护的角度来看,有400万行C ++代码(这只是一个项目)我会说:
如果成员是不可变的(即const
)或没有依赖的简单(如带有成员X和Y的点类),则不使用getter / setter。
如果成员是private
,那么也可以跳过getter / setter。如果.cpp单位很小,我也会将内部pimpl - 类的成员计为private
。
如果成员为public
或 protected
(protected
与public
一样差)且非{{1然后,使用getters / setters,非简单或具有依赖关系。
作为维修人员,我想要拥有吸气剂/安装者的主要原因是因为我有一个地方可以放置断点/记录/其他东西。
我更喜欢替代方案2的风格,因为它更易于搜索(编写可维护代码的关键组件)。
答案 1 :(得分:7)
我从不使用这种风格。因为它可以限制你的类设计的未来,并且明确的geters或setter与一个好的编译器一样有效。
当然,实际上内联显式getter或setter会在类实现上创建同样多的底层依赖。这只是减少语义依赖。如果更改它们,仍然需要重新编译所有内容。
当我使用访问器方法时,这是我的默认样式。
这种风格对我来说太“聪明”了。我确实在极少数情况下使用它,但仅限于我真的希望访问者尽可能多地感受变量。
我认为有一个简单的变量包可能是一个构造函数,以确保它们都被初始化为理智的东西。当我这样做时,我只需将其设为struct
并将其全部公开。
答案 2 :(得分:7)
2)是最好的IMO,因为它使你的意图最清晰。 set_amount(10)
比amount(10)
更有意义,因为一个好的副作用允许名为amount
的成员。
公共变量通常是一个坏主意,因为没有封装。假设您需要在更新变量时更新缓存或刷新窗口?如果您的变量是公开的,那就太糟糕了。如果你有一个set方法,你可以在那里添加它。
答案 3 :(得分:6)
如果我们只想表示pure
数据,这是一种很好的风格。
我不喜欢它:)因为当我们可以在C ++中重载它们时,get_/set_
实际上是不必要的。
STL使用此样式,例如std::streamString::str
和std::ios_base::flags
,除非应该避免!什么时候?当方法的名称与其他类型的名称冲突时,会使用get_/set_
样式,例如std::string::get_allocator
,因为std::allocator
。
答案 4 :(得分:4)
一般来说,我觉得系统中有太多实体使用过多的getter和setter并不是一个好主意。这只是一个糟糕的设计或错误的封装的迹象。
话虽如此,如果需要重构这样的设计,并且源代码可用,我宁愿使用访问者设计模式。原因是:
一个。它为班级提供了机会 决定允许谁访问它 私人州
湾它给了一个班级 有机会决定访问哪些内容 允许每个实体 对其私人州感兴趣
℃。它 明确记录这种外部访问 通过明确的类接口
基本理念是:
a)如果可能的话重新设计,
b)中 重构这样
所有对类状态的访问都是通过众所周知的 individualistic 进行的 接口
- 醇>
应该可以配置某种做什么和不该做什么 对于每个这样的界面,例如所有 从外部实体访问 GOOD 应该被允许,所有访问权限 外部实体 BAD 应该是 不允许,外部实体确定 应该被允许但不能设置(例如)
答案 5 :(得分:2)
我不会排除使用访问者。可能对某些POD结构而言,但我认为它们是好事(有些访问器也可能有其他逻辑)。
如果您的代码一致,那么命名约定并不重要。如果您使用多个第三方库,他们可能会使用不同的命名约定。所以这是一个品味问题。
答案 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);