开发者

Access members directly or always use getters

I personally find it weird/ugly when a class uses a getter to access its own member data. I know the performance impact is none but I just don't like to 开发者_开发问答see all those method calls. Are there any strong arguments either way, or is it just one of those things that's personal preference and should be left to each coder, or arbitrarily controlled in a coding standard?

Update: I'm meaning simple getters, specifically for a class' non-public members.


The reason you might want to use a getter/setter is because it conceals the implementation. You won't have to rewrite all of your code if you are using getters/setters in case the implementation does change, because those members can continue to work.

EDIT based on the many clever comments:

As for a class using setters and getters on itself, that may depend on the particulars. After all, the implementation of a particular class is available to the class itself. In the cases where a class is normally instantiated, the class should use the member values directly for its own members (private or otherwise) and its parent classes (if they are protected) and only use getters/setters in the case that those members are private to the parent class.

In the case of an abstract type, which will usually not contain any implementation at all, it should provide pure virtual getters and setters and use only those in the methods it does implement.


Willingness to use getters/setters within class member implementation is the canary in the mine telling that your class is growing unreasonably. It tells that your class is trying to do too many different things, that it serves several purposes where it should serve one instead.

In fact, this is usually encountered when you are using one part of your class to store or access your data, and another part to make operations on it. Maybe you should consider using a standalone class to store and give access to your data, and another one to provide a higher view, with more complex operations with your data.


THE OBVIOUS

getters and setters for protected members makes as much sense as for public... derived classes are just another form of client code, and encapsulating implementation details from them can still be useful. I'm not saying always do it, just to weight pros and cons along the normal lines.

getters and setters for private members is rarely a net benefit, though:

  • it does provide the same kind of encapsulation benefits

    • single place for breakpoints/logging of get/set + invariant checks during dev (if used consistently)
    • virtual potential
    • etc...

    but only to the presumably relatively small implementation of the same struct/class. In enterprise environments, and for public/protected member data, those benefits can be substantial enough to justify get/set methods: a logging function may end up having millions of lines of code depedent on it, and hundreds or thousands of libraries and apps for which a change to a header may trigger recompilation. Generally a single class implementation shouldn't be more than a few hundred (or at worst thousand) lines - not big or complex enough to justify encapsulating internal private data like this... it could be said to constitute a "code smell".

THE NOT-SO OBVIOUS

  • get/set methods can very occasionally be more readable than direct variable access (though more often less readable)
  • get/set methods may be able to provide a more uniform and convenient interface for code-generated member or friend methods (whether from macros or external tools/scripts)
  • less work required to transition between being a member or friend to a freestanding helper function should that become possible
  • implementation may be rendered more understandable (and hence maintainable) to people who're normally only users of the class (as more operations are expressed via, or in the style of, the public interface)

It's a bit out of scope for the question, but it's worth noting that classes should generally provide action-oriented commands, event-triggered callbacks etc. rather than encouraging a get/set usage pattern.


It seems most people didn't read your question properly, the question is concerning whether or not class methods accessing its own class' members should use getters and setters; not about an external entity accessing the class' members.

I wouldn't bother using getter and setter for accessing a class' own members.

However, I also keep my classes small (typically about 200-500 lines), such that if I do need to change the fields or change its implementations or how they are calculated, search and replace wouldn't be too much work (indeed, I often change variable/class/function names in the early development period, I'm picky name chooser).

I only use getter and setters for accessing my own class members when I am expecting to change the implementation in the near future (e.g. if I'm writing a suboptimal code that can be written quickly, but plans to optimize it in the future) that might involve radically changing the data structure used. Conversely, I don't use getter and setter before I already have the plan; in particular, I don't use getter and setter in expectation of changing things I'm very likely never going to change anyway.

For external interface though, I strictly adhere to the public interface; all variables are private, and I avoid friend except for operator overloads; I use protected members conservatively and they are considered a public interface. However, even for public interface, I usually still avoid having direct getters and setters methods, as they are often indicative of bad OO design (every OO programmers in any language should read: Why getter and setter methods are Evil). Instead, I have methods that does something useful, instead of just fetching the values. For example:

class Rectangle {
    private:
        int x, y, width, height;
    public:
        // avoid getX, setX, getY, setY, getWidth, setWidth, getHeight, setHeight
        void move(int new_x, int new_y);
        void resize(int new_width, int new_height);
        int area();
}


The only advantage is that it allows changing internal representation without changing external interface, permitting lazy evaluation, or why not access counting.

In my experience, the number of times I did this is very, very low. And it seems you do, I also prefer to avoid the uglyness and weightyness of getter/setters. It is not that difficult to change it afterwards if I really need it.

As you speak about a class using its own getter/setters in its own implementation functions, then you should consider writing non-friend non-member functions where possible. They improve encapsulation as explained here.


An argument in favor of using getters is that you might decide one day to change how the member field is calculated. You may decide that you need it to be qualified with some other member, for instance. If you used a getter, all you have to do is change that one getter function. If you didn't you have to change each and every place where that field is used currently and in the future.


Just a crude example. Does this help?

struct myclass{
    int buf[10];
    int getAt(int i){
        if(i >= 0 && i < sizeof(buf)){
            return buf[i];
        }
    }

    void g(){
        int index = 0;
        // some logic
        // Is it worth repeating the check here (what getAt does) to ensure
              // index is within limits
        int val = buf[index];
    }
};

    int main(){}

EDIT:

I would say that it depends. In case the getters do some kind of validation, it is better to go through the validation even if it means the class members being subjected to that validation. Another case where going through a common entry point could be helpful is when the access needs to be essentially in a sequential and synchronized manner e.g. in a multithreaded scenario.


Protecting a member variable by wrapping its access with get/set functions has its advantages. One day you may wish to make your class thread-safe - and in that instance, you'll thank yourself for using those get/set functions


this is actually for supporting the object oriented-ness of the class by abstracting the way to get(getter). and just providing its easier access.


Simple answer. If you are writing a one shoot program, that will never change, you can leave the getters at peace and do without any.

However if you write a program that could change or been written over time, or others might use that code, use getters.

If you use getters it helps change the code faster later on, like putting a guard on the property to verify correctness of value, or counting access to the property(debugging).

Getters to me are about easy possibilities(free lunch). The programmer who write the code does not need getters, he wants them.

hope that help.


My thoughts are as follows.

Everything should be static, constant, and private if possible.

  • As you need a variable to be instanced meaning more than one unique copy you remove static.

  • As you need a variable to be modifiable you remove the const.

  • As you need a class/variable to be accessed by other classes you remove the private.

The Usage of Setters/Getters - General Purpose.

  • Getter's are okay if the value is to ONLY be changed by the class and we want to protect it. This way we can retrieve the current state of this value without the chance of it's value getting changed.
  • Getter's should not be used if you are planning to provide a Setter with it. At this point you should simply convert the value to public and just modify it directly. Since this is the intent with a Get/Set.

  • A Setter is plain useless if you are planning to do more then simply "this.value = value". Then you shouldn't be calling it "SetValue" rather describe what it is actually doing.

  • If let's say you want to make modifications to a value before you "GET" it's value. Then DO NOT call it "GetValue". This is ambiguous to your intent and although YOU might know what's happening. Someone else wouldn't unless they viewed the source code of that function.

  • If let's say you are indeed only Getting/Setting a value, but you are doing some form of security. I.e. Size check, Null Check, etc.. this is an alternative scenario. However you should still clarify that in the name E.g. "SafeSetValue" , "SafeGetValue" or like in the "printf" there is "printf_s".

Alternatives to the Get/Set situations

  • An example that I personally have. Which you can see how I handle a Get/Set scenario. Is I have a GameTime class which stores all kinds of values and every game tick these values get changed.

    https://github.com/JeremyDX/DX_B/blob/master/DX_B/GameTime.cpp

  • As you will see in the above my "GETS" are not actually "GETS" of
    values except in small cases where modification wasn't needed. Rather they are descriptions of values I am trying to retrieve out of this
    GameTime class. Every value is "Static Private". I cannot do Const
    given the information is obtained until runtime and I keep this
    static as there is no purpose to have multiple instances of Timing.

  • As you will also see I don't have any way of performing a "SET" on any of this data, but there are two functions "Begin()" and "Tick()" which both change the values. This is how ALL "setters" should be handled. Basically the "Begin()" function resets all the data and loads in our constants which we CANT set as constants since this is data we retrieve at runtime. Then TICK() updates specific values as time passes in this case so we have fresh up to date information.

  • If you look far into the code you'll find the values "ResetWindowFrameTime()" and "ElapsedFrameTicks()". Typically I wouldn't do something like this and would have just set the value to public. Since as you'll see I'm retrieving the value and setting the value. This is another form of Set/Get, but it still uses naming that fits the scenario and it uses data from private variables so it didn't make sense to pull another private variable and then multiply it by this rather do the work here and pull the result. There is also NO need to edit the value other then to reset it to the current frame index and then retrieve the elapsed frames. It is used when I open a new window onto my screen so I can know how long I've been viewing this window for and proceed accordingly.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜