views:

263

answers:

8

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 get_amount(); // Returns the amount
void set_amount(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?

A: 
  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.

Cătălin Pitiș
+3  A: 
  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.

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.

Omnifarious
+1 for the "too clever". I would recommend not to abuse of the overload possibility, it just makes it harder on readers, and it's also harder to search the codebase.
Matthieu M.
+1  A: 

According to the Google C++ Style Guide:

Make data members private, and provide access to them through accessor functions as needed (for technical reasons, we allow data members of a test fixture class to be protected when using Google Test). Typically a variable would be called foo_ and the accessor function foo(). You may also want a mutator function set_foo(). Exception: static const data members (typically called kFoo) need not be private.

Gunslinger47
Of course, the google C++ style guide also says "We do not use C++ exceptions." and "In general, constructors should merely set member variables to their initial values. Any complex initialization should go in an explicit Init() method." and various other things that I would definitely not agree with in general. I would not consider it a particularly good repository of style wisdom.
Omnifarious
@Omni: If you know of another official style guideline that gives recommendations for accessors and mutators, please feel free to add them to this answer. I couldn't find anything better than Google.
Gunslinger47
The Google C++ Style basically says "Let's not program C++, let's program C with some classes" which is fine but then you wonder why use C++ at all, why not go for pure C.
FuleSnabel
+1  A: 

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.

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.

AshleysBrain
A: 

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.lenght() = 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.

Ugo
I didn't vote this down, but the very first is a very poor answer because it exposes design details that a regular accessor keeps hidden. And the other suggestion isn't worthwhile enough to redeem the answer. If you're going to attempt something like the first style, at least return some kind of object that has an `operator =` instead of a reference to an internal data member.
Omnifarious
To make things clear, my answer only completes the list of possibilities the OP started (I should have comment maybe). I do not especially recommend those possibilities. Like Omnifarious said using a proxy class overloading `operator=` in the first case is obviously a good thing to do at minimum. I would use the second one in some case if I want to provide editing functionality transverse to the class hierarchy, and when it makes sens to clearly separate this functionality from the class. It is probably a bad idea for a simple setter though.
Ugo
A: 
  1. That is a good style if we just want to represent pure data.

  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::str and 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_allocator because of std::allocator.

PC2st
I fear STL might be a bit inconsistent in that respect. Sadly, Stroustrup himself doesn't seem to have voiced an opinion on how to do getters/setters except that he dislikes classes with many of them.
Noarth
A: 

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:

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

Basic idea is:

a) Redesign if possible else,

b) Refactor such that

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

  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 GOOD should be allowed, all access from external entity BAD should be disallowed, and external entity OK should be allowed to get but not set (for example)

Chubsdad
Interesting point indeed, no idea why this was voted down. But I think I'd prefer the friend keyword if a specific class would need access to specific members.
fhd
A: 

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 (ie const) or simple with no dependencys (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 as private if the .cpp unit is smallish.

If member is public or protected (protected is just as bad as public) 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).

FuleSnabel
Accepting a specific answer for community wiki questions is always a bit weird, because every answer helps. However, I think yours is the one best justified. I'm currently trying to avoid getter/setter methods wherever possible. It takes some time to come up with alternatives, but they are often better. If I need simple data as mentioned by you, I usually use a data-only struct.
Noarth