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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3647438/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:22:01  来源:igfitidea点击:

Conventions for accessor methods (getters and setters) in C++

c++accessorsettergetter

提问by Noarth

Several questions about accessor methods in C++ have been asked on SO, but none was able satisfy my curiosity on the issue.

已经在 SO 上提出了几个关于 C++ 中访问器方法的问题,但没有一个能够满足我对这个问题的好奇心。

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.

我尽量避免使用访问器,因为像 Stroustrup 和其他著名的程序员一样,我认为一个包含许多访问器的类是糟糕的面向对象的标志。在 C++ 中,在大多数情况下,我可以为类添加更多的责任或使用朋友关键字来避免它们。然而在某些情况下,您确实需要访问特定的类成员。

There are several possibilities:

有几种可能:

1. Don't use accessors at all

1. 根本不要使用访问器

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?

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

2. Use Java-style get/set methods

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

I'm not sure if it's from Java at all, but I mean this:

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

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

3. Use objective C-style get/set methods

3. 使用客观的 C 风格的 get/set 方法

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.

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

Which style do you use and why?

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

采纳答案by Just another metaprogrammer

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:

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

  • 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 privateonly it's also ok to skip getters/setters. I also count members of internal pimpl-classes as privateif the .cpp unit is smallish.

  • If member is publicor protected(protectedis just as bad as public) and non-const, non-simple or has dependencies then use getters/setters.

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

  • 如果private只是成员,也可以跳过 getter/setter。我也算内部的成员PIMPL-班如private如果在.cpp单元短小。

  • 如果成员是publicor protected(和protected一样糟糕public) 和 non- const、非简单或有依赖项,则使用 getter/setter。

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.

作为一名维护人员,我想要拥有 getter/setter 的主要原因是因为那时我有一个地方可以放置断点/日志记录/其他东西。

I prefer the style of alternative 2. as that's more searchable (a key component in writing maintainable code).

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

回答by AshleysBrain

2) is the best IMO, because it makes your intentions clearest. set_amount(10)is more meaningful than amount(10), and as a nice side effect allows a member named amount.

2) 是最好的 IMO,因为它使您的意图最清晰。 set_amount(10)比 更有意义amount(10),并且作为一个不错的副作用允许名为amount.

Public variables is usuallya 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.

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

回答by Omnifarious

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

  2. This is my default style when I use accessor methods.

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

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

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

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

  3. 这种风格对我来说似乎太“聪明”了。我确实在极少数情况下使用它,但仅在我真的希望访问器尽可能像变量一样的情况下使用。

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 structand leave it all public.

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

回答by M. Sadeq H. E.

  1. That is a good style if we just want to represent puredata.

  2. I don't like it :) because get_/set_is really unnecessary when we can overload them in C++.

  3. STL uses this style, such as std::streamString::strand std::ios_base::flags, except when it should be avoided! when? When method's name conflicts with other type's name, then get_/set_style is used, such as std::string::get_allocatorbecause of std::allocator.

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

  2. 我不喜欢它 :) 因为get_/set_当我们可以在 C++ 中重载它们时真的没有必要。

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

回答by Chubsdad

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.

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

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:

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

a. It gives a class an opportunity to decide whom to allow access to its private state

b. It gives a class an opportunity to decide what access to allow to each of the entities who are interested in its private state

c. It clearly documents such exteral access via a clear class interface

一种。它让类有机会决定允许谁访问其私有状态

湾 它让类有机会决定允许对其私有状态感兴趣的每个实体的访问权限

C。它通过清晰的类接口清楚地记录了这种外部访问

Basic idea is:

基本思路是:

a) Redesign if possible else,

b) Refactor such that

  1. All access to class state is via a well known individualisticinterface

  2. It should be possible to configure some kind of do's and don'ts to each such interface, e.g. all access from external entity GOODshould be allowed, all access from external entity BADshould be disallowed, and external entity OKshould be allowed to get but not set (for example)

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

b) 重构使得

  1. 所有对类状态的访问都是通过一个众所周知的个人界面

  2. 应该可以为每个这样的接口配置某种做和不做的事情,例如 应该允许来自外部实体GOOD 的所有访问,应该禁止来自外部实体BAD 的所有访问,并且 应该允许外部实体OK获得但是未设置(例如)

回答by C?t?lin Piti?

  1. 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).

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

  1. 我不会排除使用访问器。可能对于某些 POD 结构,但我认为它们是一件好事(某些访问器也可能有额外的逻辑)。

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

回答by log0

An additional possibility could be :

另一种可能性是:

int& amount();

I'm not sure I would recommend it, but it has the advantage that the unusual notation can refrain users to modify data.

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

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

Sometimes it is maybe just the good choice to make:

有时它可能只是做出以下选择:

image(point) = 255;  


Another possibility again, use functional notation to modify the object.

还有一种可能,使用功能符号来修改对象。

edit::change_amount(obj, val)

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.

这样,危险/编辑功能可以在单独的命名空间中使用它自己的文档进行删除。这似乎与泛型编程自然而然。

回答by gus

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:

像下面这样的东西通常没有很好地利用 C++ 属性:

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

Why? Because the result of p.mass*p.acceleration is a float and not force as expected.

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

The definition of classes to designate a purpose (even if it's a value, like amountmentioned earlier) makes more sense, and allow us to do something like:

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

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

You can access the value in amount implicitly by the operator int. Furthermore:

您可以通过运算符 int 隐式访问数量值。此外:

struct wage
{
    amount balance;

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

Getter/Setter usage:

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
}

This is a different approach, doesn't mean it's good or bad, but different.

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

回答by Rok Kralj

Let me tell you about one additional possiblity, which seems the most conscise.

让我告诉你另一种可能性,它似乎是最简洁的。

Need to read & modify

需要阅读和修改

Simply declare that variable public:

只需将该变量声明为 public:

class Worker {
public:
    int wage = 5000;
}

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

Need just to read

只需要阅读

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

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

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.

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