C++ 中访问器方法(getter 和 setter)的约定;
关于 C++ 中的访问器方法的几个问题已经在 SO 上被问到了,但没有一个能够满足我对此问题的好奇心。
我尽可能避免访问器,因为像 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 风格的 get/set 方法
这有点奇怪,但显然越来越常见:
int amount(); // Returns the amount
void amount(int amount); // Sets the amount
为了使其工作,您必须为您的成员变量找到一个不同的名称。有些人附加下划线,其他人则附加“m_”。我也不喜欢。
您使用哪种风格?为什么?
Several questions about accessor methods in C++ have been asked on SO, but none was able satisfy my curiosity on the issue.
I try to avoid accessors whenever possible, because, like Stroustrup and other famous programmers, I consider a class with many of them a sign of bad OO. In C++, I can in most cases add more responsibility to a class or use the friend keyword to avoid them. Yet in some cases, you really need access to specific class members.
There are several possibilities:
1. Don't use accessors at all
We can just make the respective member variables public. This is a no-go in Java, but seems to be OK with the C++ community. However, I'm a bit worried about cases were an explicit copy or a read-only (const) reference to an object should be returned, is that exaggerated?
2. Use Java-style get/set methods
I'm not sure if it's from Java at all, but I mean this:
int getAmount(); // Returns the amount
void setAmount(int amount); // Sets the amount
3. Use objective C-style get/set methods
This is a bit weird, but apparently increasingly common:
int amount(); // Returns the amount
void amount(int amount); // Sets the amount
In order for that to work, you will have to find a different name for your member variable. Some people append an underscore, others prepend "m_". I don't like either.
Which style do you use and why?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
让我告诉你另一种可能性,这似乎是最简洁的。
需要阅读&修改
只需声明该变量 public:
只需要 read
这种方法的缺点是,当您想要更改访问模式时,您需要更改所有调用代码(即添加括号)。
Let me tell you about one additional possiblity, which seems the most conscise.
Need to read & modify
Simply declare that variable public:
Need just to read
The downside of this approach is that you need to change all the calling code (add parentheses, that is) when you want to change the access pattern.
#3 的变体,我被告知这可能是“流畅”的风格
variation on #3, i'm told this could be 'fluent' style
从我的角度来看,从维护的角度来看,拥有 400 万行 C++ 代码(这只是一个项目),我会说:
如果成员是不可变的(即
const) 或没有依赖关系的简单(如具有成员 X 和 Y 的点类)。
如果成员是
私有
,那么跳过 getters/setters 也是可以的。如果 . cpp 单元很小。如果成员是
public
或protected
(protected
与public
一样糟糕code>) 和非 const、非简单或具有依赖项,则使用 getter/setter。作为一名维护人员,我想要拥有 getter/setter 的主要原因是因为这样我就有地方放置断点/日志记录/其他东西。
我更喜欢替代方案 2. 的风格,因为它更易于搜索(编写可维护代码的关键组成部分)。
From my perspective as sitting with 4 million lines of C++ code (and that's just one project) from a maintenance perspective I would say:
It's ok to not use getters/setters if members are immutable (i.e.
const
) or simple with no dependencies (like a point class with members X and Y).If member is
private
only it's also ok to skip getters/setters. I also count members of internal pimpl-classes asprivate
if the .cpp unit is smallish.If member is
public
orprotected
(protected
is just as bad aspublic
) and non-const
, non-simple or has dependencies then use getters/setters.As a maintenance guy my main reason for wanting to have getters/setters is because then I have a place to put break points / logging / something else.
I prefer the style of alternative 2. as that's more searchable (a key component in writing maintainable code).
2)是最好的IMO,因为它让你的意图最清晰。
set_amount(10)
比amount(10)
更有意义,并且一个很好的副作用是允许名为amount
的成员。公共变量通常是一个坏主意,因为没有封装。假设您需要在更新变量时更新缓存或刷新窗口?如果你的变量是公共的那就太糟糕了。如果您有设置方法,则可以将其添加到此处。
2) is the best IMO, because it makes your intentions clearest.
set_amount(10)
is more meaningful thanamount(10)
, and as a nice side effect allows a member namedamount
.Public variables is usually a bad idea, because there's no encapsulation. Suppose you need to update a cache or refresh a window when a variable is updated? Too bad if your variables are public. If you have a set method, you can add it there.
我从不使用这种风格。因为它会限制类设计的未来,并且显式的 getter 或 setter 与良好的编译器一样高效。
当然,实际上,内联显式 getter 或 setter 会创建对类实现同样多的底层依赖。它们只是减少语义依赖性。如果更改它们,您仍然必须重新编译所有内容。
这是我使用访问器方法时的默认样式。
这种风格对我来说似乎太“聪明”了。我确实在极少数情况下使用它,但仅在我真正希望访问器尽可能感觉像变量的情况下。
我确实认为有一个简单的变量袋可能带有构造函数的情况,以确保它们都被初始化为正常的东西。当我这样做时,我只需将其设为一个
struct
并将其全部公开。I never use this style. Because it can limit the future of your class design and explicit geters or setters are just as efficient with a good compilers.
Of course, in reality inline explicit getters or setters create just as much underlying dependency on the class implementation. THey just reduce semantic dependency. You still have to recompile everything if you change them.
This is my default style when I use accessor methods.
This style seems too 'clever' to me. I do use it on rare occasions, but only in cases where I really want the accessor to feel as much as possible like a variable.
I do think there is a case for simple bags of variables with possibly a constructor to make sure they're all initialized to something sane. When I do this, I simply make it a
struct
and leave it all public.如果我们只想表示
纯
数据,这是一个很好的风格。我不喜欢它:)因为当我们可以在C++中重载它们时,
get_/set_
实际上是不必要的。STL 使用这种样式,例如
std::streamString::str
和std::ios_base::flags
,除非应该避免!什么时候?当方法的名称与其他类型的名称冲突时,则使用get_/set_
样式,例如std::string::get_allocator
因为std::allocator< /code>.
That is a good style if we just want to represent
pure
data.I don't like it :) because
get_/set_
is really unnecessary when we can overload them in C++.STL uses this style, such as
std::streamString::str
andstd::ios_base::flags
, except when it should be avoided! when? When method's name conflicts with other type's name, thenget_/set_
style is used, such asstd::string::get_allocator
because ofstd::allocator
.总的来说,我觉得系统中太多的实体使用太多的 getter 和 setter 并不是一个好主意。这仅表明设计不良或封装错误。
话虽如此,如果这样的设计需要重构,并且源代码可用,我更愿意使用访问者设计模式。原因是:
基本思想是:
In general, I feel that it is not a good idea to have too many getters and setters being used by too many entities in the system. It is just an indication of a bad design or wrong encapsulation.
Having said that, if such a design needs to be refactored, and the source code is available, I would prefer to use the Visitor Design pattern. The reason is:
Basic idea is:
我不会排除访问器的使用。对于某些 POD 结构可能是这样,但我认为它们是一件好事(某些访问器也可能有额外的逻辑)。
如果代码保持一致,命名约定并不重要。如果您使用多个第三方库,它们可能会使用不同的命名约定。所以这是一个品味问题。
I would not exclude accessors from use. May for some POD structures, but I consider them a good thing (some accessors might have additional logic, too).
It doesn't realy matters the naming convention, if you are consistent in your code. If you are using several third party libraries, they might use different naming conventions anyway. So it is a matter of taste.
我已经看到类的理想化而不是整数类型来引用有意义的数据。
像下面这样的东西通常没有很好地利用 C++ 属性:
为什么?因为 p.mass*p.acceleration 的结果是浮点数,而不是预期的力。
指定用途的类定义(即使它是一个值,如前面提到的 amount)更有意义,并允许我们执行以下操作:
您可以通过运算符隐式访问 amount 中的值国际。此外:
Getter/Setter 用法:
这是一种不同的方法,并不意味着它是好还是坏,而是不同。
I've seen the idealization of classes instead of integral types to refer to meaningful data.
Something like this below is generally not making good use of C++ properties:
Why? Because the result of p.mass*p.acceleration is a float and not force as expected.
The definition of classes to designate a purpose (even if it's a value, like amount mentioned earlier) makes more sense, and allow us to do something like:
You can access the value in amount implicitly by the operator int. Furthermore:
Getter/Setter usage:
This is a different approach, doesn't mean it's good or bad, but different.
另一种可能性是:
我不确定我是否会推荐它,但它的优点是不寻常的符号可以阻止用户修改数据。
有时这可能是一个不错的选择:
另一种可能性是,使用函数符号来修改对象。
这样,危险/编辑功能就可以通过它自己的文档放在一个单独的命名空间中。这似乎是泛型编程中自然而然的事情。
An additional possibility could be :
I'm not sure I would recommend it, but it has the advantage that the unusual notation can refrain users to modify data.
Sometimes it is maybe just the good choice to make:
Another possibility again, use functional notation to modify the object.
This way dangerous/editing function can be pulled away in a separate namespace with it's own documentation. This one seems to come naturally with generic programming.