Public Data members vs Getters, Setters
Asked Answered
D

15

87

I am currently working in Qt and so C++. I am having classes that has private data members and public member functions. I have public getters and setters for the data members available in the class.

Now my question is, if we have getters and setters for data members in our classes then what's the point in making those data members as private? I agree having private data members in Base classes sounds logical. But besides that, having private members and so do their getters and setters doesn't seem to be of a logical one for me.

Or instead can we make all variables as public so that no need for getters and setters at all? Is it a good practice to have those? I know having private members ensure data abstraction but having getters and setters actually lets access to those variables quite easily. Any pointers regarding this are welcome.

Deduction answered 4/6, 2010 at 19:8 Comment(1)
To control modification of a variable of one class in another class, By making the variable private we can control the way value gets modified , For example if in another class if the variable gets modified to negative using a setter we can throw an exception to not set to negative. In doing this the variable has to be turned into private , and to access that private variable we can use getter.Superabundant
S
86

Neither. You should have methods that do things. If one of those things happens to correspond with a specific internal variable that's great but there should be nothing that telegraphs this to the users of your class.

Private data is private so you can replace the implementation whenever you wish (and can do full rebuilds but that's a different issue). Once you let the Genie out of the bottle you will find it impossible to push it back in.

EDIT: Following a comment I made to another answer.

My point here is that you are asking the wrong question. There is no best practice with regard to using getters/setters or having public members. There is only what is best for your specific object and how it models some specific real world thing (or imaginary thing perhaps in the case of game).

Personally getters/setters are the lesser of two evils. Because once you start making getters/setters, people stop designing objects with a critical eye toward what data should be visible and what data should not. With public members it is even worse because the tendency becomes to make everything public.

Instead, examine what the object does and what it means for something to be that object. Then create methods that provide a natural interface into that object. It that natural interface involves exposing some internal properties using getters and setters so be it. But the important part is that you thought about it ahead of time and created the getters/setters for a design justified reason.

Scurf answered 4/6, 2010 at 19:13 Comment(2)
Another useful difference: You can easily place a debugging breakpoint on a member function, but it's much harder to place a debugging breakpoint on a memory location for all instantiations of a class. This starts to lead to questions like: Do I need to know when this is changed or accessed? Are there any relationships between these data members that must be maintained? What are the multithreading safety requirements?Subliminal
@JasonHarrison I see your point but you can always place a Watchpoint in most IDEs on a public variable to see when the value of that variable changes.Parsley
E
42

No, it is not even remotely the same thing.

There are different levels of protection/implementation hiding that can be achieved by different approaches to a class interface:


1. Public data member:

  • provides both read and write (if not const) access to the data member
  • exposes the fact that data object physically exists and is physically a member of this class (allows one to create pointers of pointer-to-member type to that data member)
  • provides lvalue access to the data member (allows one to create ordinary pointers to the member)


2. A method that returns a reference to a piece of data (possibly to a private data member):

  • provides both read and write (if not const) access to the data
  • exposes the fact that data object physically exists but does not expose that it is physically a member of this class (does not allow one to create pointers of pointer-to-member type to the data)
  • provides lvalue access to the data (allows one to create ordinary pointers to it)


3. Getter and/or setter methods (possibly accessing a private data member):

  • provides both read and/or write access to the property
  • does not expose the fact that data object physically exists, let alone physically present in this class (does not allow one to create pointers of pointer-to-member type to that data, or any kind of pointers for that matter)
  • does not provide lvalue access to the data (does not allow one to create ordinary pointers to it)

The getter/setter approach does not even expose the fact that the property is implemented by a physical object. I.e. there might be no physical data member behind the getter/setter pair.

Taking above into the account, it is strange to see someone claim that a getter and setter pair is the same as a public data member. In fact, they have nothing in common.

Of course, there are variations of each approach. A getter method, for example, might return a const reference to the data, which would place it somewhere between (2) and (3).

Endmost answered 4/6, 2010 at 19:29 Comment(5)
@ AndreyT, really a good one... But is it a good practice having getters and setters for private members?? At least to those members who might be retrieved and modified so often...Deduction
They may not be the same, but they're used for the same purpose - providing public access to a property of an object.Formalize
You are looking at this form the C++ language point of view - my answer is from the application design perspective.Colitis
+1 for pointing out that a getter need not return a reference or pointer to the data. Being able to get a copy is a lot different than being able to get the lvalue.Colville
@Deduction - It has nothing to do with what is good practice and everything to do with what does your object model. See my answer above. You are asking the wrong question.Scurf
C
26

If you have getters and setters for each of your data items, there is no point in making the data private. That's why having getters and setters for each of your data items is a bad idea. Consider the std::string class - it (probably) has ONE getter, the size() function, and no setters at all.

Or consider a BankAccount object - should we have SetBalance() setter to change the current balance? No, most banks won't thank you for implementing such a thing. Instead, we want something like ApplyTransaction( Transaction & tx ).

Colitis answered 4/6, 2010 at 19:10 Comment(8)
you mean to say that we should avoid having getters and setters for the data members?Deduction
+1 for each of the answer and the comment. It is hard to have an invariant defined for a class if everything is effectively public. If there is no invariant there really is no class.Gill
+1 you want to have an interface by "task"/"operation", not getters/setters or public data.Caught
Neil, I think that's not a good suggestion. Getters and setters are CRUCIAL to Qt's property system. You can't have properties without them. Also, getters and setters can do other necessary stuff, like lock a mutex, query a database, implicit sharing, reference counting, lazy loading and so on.Coycoyle
@iconiK Although the OP mentioned Qt, the question is not tagged as such. Personally, I'm quite anti properties (and I'm an ex Delphi programmer, so I know whereof I speak), particularly in the business model, but they are also difficult (sometimes impossible) to implement in GUIs where you have several related properties with constraints on all of them.Colitis
Your first sentence kind of threw me off. There is still a point in making the data private even if you have getters and setters for it. That seems orthogonal to your larger point, that it's okay (even desirable) to have private data without getters and setters.Charlettecharley
@Bill You are right - exaggeration for effect there. My point is the general badness of get/set functions.Colitis
Setters/Getters do have some purpose. For example, in C++0x, if you had a public variable, you could call std::move on it. I guess there are ways to do this anyway, but it helps. It also protects users from implementation change. I wouldn't use them in systems that are finished development, only during development to make code more re-usable.Maldon
A
14

Make the data public. In the (rather unlikely) event that you do someday need logic in the "getter" or "setter", you can change the data type to a proxy class that overloads operator= and/or operator T (where T=whatever type you're using now) to implement the necessary logic.

Edit: the idea that controlling access to the data constitutes encapsulation is basically false. Encapsulation is about hiding the details of the implementation (in general!) not controlling access to data.

Encapsulation is complementary to abstraction: abstraction deals with the object's externally visible behavior, while encapsulation deals with hiding the details of how that behavior is implemented.

Using a getter or setter actually reduces the level of abstraction and exposes the implementation -- it requires client code to be aware that this particular class implements what is logically "data" as a pair of functions (the getter and setter). Using a proxy as I've suggested above provides real encapsulation -- except for one obscure corner case, it completely hides the fact that what is logically a piece of data is actually implemented via a pair of functions.

Of course, this needs to be kept in context: for some classes, "data" isn't a good abstraction at all. Generally speaking, if you can provide higher level operations instead of data, that's preferable. Nonetheless, there are classes for which the most usable abstraction is reading and writing data -- and when that's the case, the (abstracted) data should be made visible just like any other data. The fact that getting or setting the value may involve more than simple copying of bits is an implementation detail that should be hidden from the user.

Annapolis answered 4/6, 2010 at 19:13 Comment(11)
"Rather unlikely"? How do you know? There are many reasons logic may be added in the future - logging, thread safety, validation, etc.Fetation
"you can change the data type to a proxy class" - yes you can, but it's a band-aid that is likely to be more trouble than it's worth.Formalize
Whether or not getters/setters are good design, "there is a hackish workaround" is not an argument, it's an excuse.Oh
@BlueRaja: Nonsense. See the edit. The fact is, either the data should be entirely invisible (not public, and no getter or setter either) or else it should be visible as data, in which case a getter and setter are exposing the wrong abstraction.Annapolis
@Rob: Simple statistics -- even in code that's been maintained for decades, the vast majority of getters/setters remain nothing but simple pass-throughs that aren't accomplishing anything useful at all.Annapolis
@Mark: Providing the right abstraction is not a band-aid; it's the right thing to do. That's well worthwhile.Annapolis
If I have 2 member variables of the same type your hack doesn't work. I much prefer to have a setter in the form void variablename (variabletype) and a getter in the form variabletype variablename() if I absolutely need to have both a getter and a setter for a class member.Colville
@tloach: You clearly don't understand what's being advocated. Having two (or a dozen) member variables of the same type doesn't prevent it from working, and doesn't even cause the slightest problem.Annapolis
Whether you agree with what he's saying or not, this is an extremely well argued point.Flattop
@Jerry is right. Either make the data public, or make the class abstract and move the data to a subclass. the middle ground - private data w/public getters & setters - is the hack.Suppletion
I'm starting to use something like this. To me, the most flexible approach is for classes to have most data private, but some public, as long as that public data is a class. I generally avoid getX() and setX() functions, preferring higher-level traits of the class, even if that happens to be implemented as just returning a variable. However, if I want read / write access for all, but there are certain constraints on that value, then my setX member function verifies that the constraints are met and throws if they aren't. If I get more complex than that, a new, public class seems better.Stylolite
H
12

Getters and Setters let you apply logic to the input/output from the private members therefore controlling access to the data (Encapsulation to those who know their OO terms).

Public variables leave your class' data open to the public for uncontrolled and non-validated manipulation which is almost always un-desirable.

You have to think about these things long term as well. You may not have validation now (which is why public variables seem to be a good idea) but there's a chance they'll be added down the road. Adding them ahead of time leaves the framework so there's less re-factoring down the raod not to mention the validation won't break dependent code this way).

Keep in mind, though, that doesn't mean Each and Every private variable needs its own getter/setter. Neil brings up a good point in his banking example that sometimes Getters/Setters just don't make sense.

Hays answered 4/6, 2010 at 19:9 Comment(0)
D
5

If you are quite sure your logic is simple, and you never need to do something else when reading/writing a variable, it's better to keep the data public. In C++ case, I prefer to use struct instead of class to emphasize the fact that the data is public.

However, quite often you need to do some other things when accessing data members, or you want to give yourself freedom to add this logic later. In this case, getters and setters are good idea. Your change will be transparent to the clients of your code.

A simple example of additional functionality - you may want log a debug string every time you access a variable.

Dayledaylight answered 4/6, 2010 at 19:16 Comment(0)
O
5

Aside from the encapsulation concerns (which are reason enough), it is very easy to set a breakpoint whenever the variable is set/accessed when you have getters/setters.

Oh answered 4/6, 2010 at 19:18 Comment(0)
P
4

Reasons to use public fields rather than getters and setters include:

  1. There are no illegal values.
  2. The client is expected to edit it.
  3. To be able to write things such as object.X.Y = Z.
  4. To making a strong promise that the value is just a value and there are no side-effects associated with it (and won't be in the future either).

Depending on what sort of software you work on, these might all be really exceptional cases (and if you think you've come across one you're probably wrong) or they might occur all the time. It really depends.

(From Ten Questions on Value-Based Programming.)

Prioress answered 25/6, 2015 at 14:7 Comment(0)
E
3

On a strictly practical basis, I'd suggest you start by making all of your data members private, AND make their getters and setters private. As you find out what the rest of the world (i.e., your "(l)user community") actually needs, you can expose the appropriate getters and/or setters, or write appropriately-controlled public accessors.

Also (for Neil's benefit), during debugging time, it is sometimes useful to have a convenient place to hang debug prints, and other actions, when a particular data member is read or written. With getters and setters, this is easy. With public data members, it is a huge pain in the posterior.

Enrica answered 4/6, 2010 at 19:16 Comment(1)
I find private get/set functions quite useful during development, even when they have no business in the public interface.Flattop
W
3

I've always thought that getters and setters are deliberately verbose in most programming languages specifically to make you think twice about using them - why does your caller need to know about the inner workings of your class should be the question at the front of your mind.

Winthrop answered 4/6, 2010 at 19:27 Comment(0)
L
3

I believe that using getters and setters simply for getting and setting the value is useless. There is no difference between a public member and private one with such methods. Use getters and setters only when you need to control the values somehow or when you think that it might be useful in the future (adding some logic won't make you edit the rest of the code).

As a reference, read C++ guidelines (C.131)

Luxembourg answered 10/10, 2017 at 16:52 Comment(0)
E
1

I suggest that you don't have public data members (except for POD structs). I also don't recommend that you have getters and setters for all of your data members. Rather, define a clean public interface for your class. This may include methods that get and/or set property values, and those properties may be implemented as member variables. But don't make getters and setters for all of your members.

The idea is that you separate your interface from your implementation, allowing you to modify the implementation without the users of the class having to change their code. If you expose everything through getters and setters, you've not improved anything over using public data.

Eous answered 4/6, 2010 at 19:14 Comment(1)
PODS (structs) represent a significant exception to the "no public data members" rule; it's too bad Microsoft didn't make an exception for them in the design of some .net value types. Read/write struct properties in .net have weird quirky behaviors which exposed struct fields do not.Presentment
B
1

Using getters and setters will allow you to modify the way that you give the values to the user.

Consider the following:

double premium;
double tax;

You then write code all over the place using this premium value to get the premium:

double myPremium = class.premium;

Your specs just changed and premium from the user's standpoint needs to be premium + tax

You will have to modify everywhere that that premium value is being used in your code, and add tax to it.

If instead you implemented it as such:

double premium;
double tax;

double GetPremium(){return premium;};

All of your code would be using GetPremium() and your tax change would be one line:

double premium;
double tax;

double GetPremium(){return premium + tax;};
Bystander answered 4/6, 2010 at 19:33 Comment(2)
And then when you need the premium without the tax what do you call the new getter? Instead create a method to calculate something real world on your object and let it decide if its going to combine premium and tax.Scurf
Yes, I suppose my example is not a true getter/setter. I was simply trying to illustrate that getters and setters let you write the implementation independent of what goes on behind the hood. I suppose a better example would be if the variable premium changed to m_dPremium or something.Bystander
E
0

The return value also effects the use of getters and setters. It's a difference to get the value of a variable or to get access to private data member variable. By-value keeps integrity, by-reference or by-pointer not so much.

Egidius answered 4/6, 2010 at 19:15 Comment(0)
I
0

Getters and Setters exist primarily so that we can control how members are fetched, and how they are set. Getters and setters dont exist only as a way to access a specific member, but to ensure that before we try and set a member, that it perhaps meets certain conditions, or if we fetch it, we could control that we return a copy of that member in the case of a non-primitive type. Overall, you should try and use g/s'ers when you want to pipeline how a data member is to be interacted with, without them would cause the member is be used in an adhoc fashion.

Intercessory answered 27/10, 2014 at 19:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.